org.jorge.cmp.service.ChatIntentService.java Source code

Java tutorial

Introduction

Here is the source code for org.jorge.cmp.service.ChatIntentService.java

Source

package org.jorge.cmp.service;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;

import com.crashlytics.android.Crashlytics;
import com.github.theholywaffle.lolchatapi.ChatServer;
import com.github.theholywaffle.lolchatapi.LoLChat;
import com.github.theholywaffle.lolchatapi.listeners.ChatListener;
import com.github.theholywaffle.lolchatapi.listeners.FriendListener;
import com.github.theholywaffle.lolchatapi.wrapper.Friend;

import org.jivesoftware.smack.SmackAndroid;
import org.jivesoftware.smack.SmackException;
import org.jorge.cmp.LoLin1Application;
import org.jorge.cmp.R;
import org.jorge.cmp.chat.ChatHistoryManager;
import org.jorge.cmp.chat.ChatNotificationManager;
import org.jorge.cmp.datamodel.ChatMessageWrapper;
import org.jorge.cmp.datamodel.LoLin1Account;
import org.jorge.cmp.util.Utils;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;

import javax.net.ssl.SSLException;

/**
 * This file is part of LoLin1.
 * <p/>
 * LoLin1 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <p/>
 * LoLin1 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * <p/>
 * You should have received a copy of the GNU General Public License
 * along with LoLin1. If not, see <http://www.gnu.org/licenses/>.
 * <p/>
 * Created by Jorge Antonio Diaz-Benito Soriano.
 */
public class ChatIntentService extends IntentService {

    public static final String ACTION_CONNECT = "CONNECT", ACTION_DISCONNECT = "DISCONNECT";
    public static final String KEY_MESSAGE_CONTENTS = "MESSAGE_CONTENTS";
    public static final String KEY_MESSAGE_SOURCE = "SOURCE_FRIEND";
    public static final String EXTRA_KEY_LOLIN1_ACCOUNT = "KEY_LOLIN1_ACCOUNT";
    private final IBinder mBinder = new ChatBinder();
    private static LoLChat api;
    private SmackAndroid mSmackAndroid;
    private static Boolean isConnected = Boolean.FALSE;
    private AsyncTask<LoLin1Account, Void, Void> mLoginTask;

    public ChatIntentService() {
        super(ChatIntentService.class.getName());
    }

    @SuppressWarnings("unused")
    public static List<Friend> getOnlineFriends() {
        return api.getOnlineFriends();
    }

    @SuppressWarnings("unused")
    public static Boolean isLoggedIn() {
        return isConnected;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        isConnected = Boolean.FALSE;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent == null) {
            throw new IllegalArgumentException("No intent found");
        }
        if (TextUtils.isEmpty(intent.getAction())) {
            throw new IllegalArgumentException("Empty action is not supported");
        }
        final LoLin1Account acc = intent.getParcelableExtra(EXTRA_KEY_LOLIN1_ACCOUNT);
        switch (intent.getAction()) {
        case ACTION_CONNECT:
            connect(acc);
            break;
        case ACTION_DISCONNECT:
            disconnect();
            break;
        default:
            throw new IllegalArgumentException("Action " + intent.getAction() + " not yet supported");
        }
    }

    public class ChatBinder extends Binder {
        @SuppressWarnings("unused")
        public ChatIntentService getService() {
            return ChatIntentService.this;
        }
    }

    private void connect(final LoLin1Account acc) {
        mSmackAndroid = LoLChat.init(getApplicationContext());
        mLoginTask = new AsyncTask<LoLin1Account, Void, Void>() {
            @Override
            protected Void doInBackground(LoLin1Account... params) {
                Boolean loginSuccess = login(params[0]);
                if (loginSuccess) {
                    launchBroadcastLoginSuccessful();
                    setUpChatOverviewListener();
                } else {
                    launchBroadcastLoginFailed();
                }
                return null;
            }
        };
        mLoginTask.executeOnExecutor(Executors.newSingleThreadExecutor(), acc);
    }

    private void setUpChatOverviewListener() {
        api.addFriendListener(new FriendListener() {

            @Override
            public void onFriendLeave(Friend friend) {
                ChatIntentService.this.launchBroadcastChatEvent();
            }

            @Override
            public void onFriendJoin(Friend friend) {
                ChatIntentService.this.launchBroadcastChatEvent();
            }

            @Override
            public void onFriendAvailable(Friend friend) {
                ChatIntentService.this.launchBroadcastChatEvent();
            }

            @Override
            public void onFriendAway(Friend friend) {
                ChatIntentService.this.launchBroadcastChatEvent();
            }

            @Override
            public void onFriendBusy(Friend friend) {
                ChatIntentService.this.launchBroadcastChatEvent();
            }

            @Override
            public void onFriendStatusChange(Friend friend) {
                ChatIntentService.this.launchBroadcastChatEvent();
            }
        });

        api.addChatListener(new ChatListener() {
            @Override
            public void onMessage(Friend friend, String message) {
                final Context context = LoLin1Application.getInstance().getContext();

                ChatMessageWrapper messageWrapper = new ChatMessageWrapper(message, System.currentTimeMillis(),
                        friend);

                ChatHistoryManager.addMessageToFriendChat(messageWrapper, friend);

                launchBroadcastMessageReceived(message, friend.getName());

                new AsyncTask<Object, Void, Boolean>() {

                    private Context mContext;
                    private String mMessage;
                    private Friend mFriend;

                    @Override
                    protected Boolean doInBackground(Object... params) {
                        mContext = (Context) params[0];
                        mMessage = (String) params[1];
                        mFriend = (Friend) params[2];

                        return Utils.isRunningOnForeground(mContext);
                    }

                    @Override
                    protected void onPostExecute(Boolean isOnForeground) {
                        if (!isOnForeground)
                            ChatNotificationManager.createOrUpdateMessageReceivedNotification(mContext, mMessage,
                                    mFriend);
                    }
                }.executeOnExecutor(Executors.newSingleThreadExecutor(), context, message, friend);
            }
        });
    }

    @SuppressWarnings("unused")
    private void launchBroadcastMessageReceived(String message, String sourceFriendName) {
        Intent intent = new Intent();
        intent.setAction(getString(R.string.event_message_received));
        intent.putExtra(KEY_MESSAGE_CONTENTS, message);
        intent.putExtra(KEY_MESSAGE_SOURCE, sourceFriendName);
        sendLocalBroadcast(intent);
    }

    private void sendLocalBroadcast(Intent intent) {
        LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
    }

    private void launchBroadcastLoginSuccessful() {
        Intent intent = new Intent();
        intent.setAction(getString(R.string.event_login_successful));
        sendLocalBroadcast(intent);
    }

    private void launchBroadcastLoginFailed() {
        Intent intent = new Intent();
        intent.setAction(getString(R.string.event_login_failed));
        sendLocalBroadcast(intent);
    }

    private void launchBroadcastChatEvent() {
        Intent intent = new Intent();
        intent.setAction(getString(R.string.event_chat_overview));
        sendLocalBroadcast(intent);
    }

    private Boolean login(final LoLin1Account acc) {
        ChatServer chatServer;
        chatServer = ChatServer.valueOf(acc.getRealmEnum().name().toUpperCase(Locale.ENGLISH));
        try {
            api = new LoLChat(LoLin1Application.getInstance().getContext(), ConnectivityManager.CONNECTIVITY_ACTION,
                    chatServer, Boolean.FALSE);
        } catch (IOException e) {
            Crashlytics.logException(e);
            e.printStackTrace(System.err);
            if (!(e instanceof SSLException)) {
                launchBroadcastLoginFailed();
            }
            return Boolean.FALSE;
        }
        Boolean loginSuccess = Boolean.FALSE;
        try {
            loginSuccess = api.login(acc.getUsername(), acc.getPassword());
        } catch (IOException e) {
            Crashlytics.logException(e);
        }
        if (loginSuccess) {
            api.reloadRoster();
            isConnected = Boolean.TRUE;
            return Boolean.TRUE;
        } else {
            isConnected = Boolean.FALSE;
            return Boolean.FALSE;
        }
    }

    private void disconnect() {
        //All the null checks are necessary because this method is run when an account is added
        // from out of the app as well
        try {
            if (mLoginTask != null)
                mLoginTask.get(); // Disconnecting in the middle of a login may be troublesome
        } catch (InterruptedException | ExecutionException e) {
            Crashlytics.logException(e);
        }
        try {
            if (api != null) {
                api.disconnect();
                api = null;
            }
        } catch (SmackException.NotConnectedException e) {
            Crashlytics.logException(e);
        }
        if (mSmackAndroid != null)
            mSmackAndroid.onDestroy();
        isConnected = Boolean.FALSE;
    }
}