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