/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
Copyright 2012 Daniel E. Moctezuma <democtezuma@gmail.com>
This file is part of Yaaic.
Yaaic 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.
Yaaic 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.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package indrora.atomic.irc;
import indrora.atomic.Atomic;
import indrora.atomic.R;
import indrora.atomic.activity.ConversationActivity;
import indrora.atomic.activity.ServersActivity;
import indrora.atomic.db.Database;
import indrora.atomic.model.Broadcast;
import indrora.atomic.model.Conversation;
import indrora.atomic.model.Message;
import indrora.atomic.model.Server;
import indrora.atomic.model.ServerInfo;
import indrora.atomic.model.Settings;
import indrora.atomic.model.Status;
import indrora.atomic.model.Message.MessageColor;
import indrora.atomic.receiver.ReconnectReceiver;
import indrora.atomic.utils.MircColors;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import javax.net.ssl.SSLException;
import javax.net.ssl.X509TrustManager;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder;
import android.util.Log;
import de.duenndns.ssl.MemorizingTrustManager;
/**
* The background service for managing the irc connections
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class IRCService extends Service {
public static final String ACTION_FOREGROUND = "indrora.atomic.service.foreground";
public static final String ACTION_BACKGROUND = "indrora.atomic.service.background";
public static final String ACTION_ACK_NEW_MENTIONS = "indrora.atomic.service.ack_new_mentions";
public static final String EXTRA_ACK_SERVERID = "indrora.atomic.service.ack_serverid";
public static final String EXTRA_ACK_CONVTITLE = "indrora.atomic.service.ack_convtitle";
private static final int FOREGROUND_NOTIFICATION = 1;
private static final int NOTIFICATION_LED_OFF_MS = 1000;
private static final int NOTIFICATION_LED_ON_MS = 300;
private static final int NOTIFICATION_LED_COLOR = 0xff00ff00;
@SuppressWarnings("rawtypes")
private static final Class[] mStartForegroundSignature = new Class[]{int.class, Notification.class};
@SuppressWarnings("rawtypes")
private static final Class[] mStopForegroundSignature = new Class[]{boolean.class};
@SuppressWarnings("rawtypes")
private static final Class[] mSetForegroudSignaure = new Class[]{boolean.class};
private final IRCBinder binder;
private final HashMap<Integer, IRCConnection> connections;
private boolean foreground = false;
private final ArrayList<String> connectedServerTitles;
private final LinkedHashMap<String, Conversation> mentions;
private int newMentions = 0;
private NotificationManager notificationManager;
private Method mStartForeground;
private Method mStopForeground;
private final Object[] mStartForegroundArgs = new Object[2];
private final Object[] mStopForegroundArgs = new Object[1];
//private Notification notification;
private Settings settings;
/**
* *
* <p/>
* This class will handle the network changes.
*/
private class NetworkTransitionHandler extends BroadcastReceiver {
// Sets up the Transition handler -- the context here is so that the connectivity manager can be found.
private NetworkTransitionHandler(Context ctx) {
NetworkInfo networkInfo = ((ConnectivityManager)(ctx.getSystemService(Service.CONNECTIVITY_SERVICE))).getActiveNetworkInfo();
if( networkInfo == null )
lastNetworkType = -1;
else
lastNetworkType = networkInfo.getType();
}
// previous network kind we were on (-1 => We do not know yet)
private int lastNetworkType = -1;
private static final String TAG = "NetworkTransitions";
// This is called when we get an intent for connectivty
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if( !action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ) {
return;
}
// _isTransient means "network is in transition -> we should know this.
IRCService.this._isTransient = true;
NetworkInfo networkInfo = ((ConnectivityManager)(context.getSystemService(Service.CONNECTIVITY_SERVICE))).getActiveNetworkInfo();
int newNetworkType = -1;
if( networkInfo == null ) {
Log.d(TAG, "Lost all connectivity.");
lastNetworkType = -1;
// There's a bug here when no network is availible at all -- I'm not certain what is really going on.
_isTransient = false;
return;
} else if( networkInfo.isConnected() ) {
Log.d(TAG, "new network type: " + networkInfo.getTypeName());
newNetworkType = networkInfo.getType();
}
if( newNetworkType != lastNetworkType ) {
Log.d(TAG, "Transition from network " + lastNetworkType + " to " + newNetworkType);
IRCService.this.networksChanged(newNetworkType);
lastNetworkType = newNetworkType;
}
}
}
private static NetworkTransitionHandler _netTransitionHandler;
private static ArrayList<Integer> reconnectNextNetwork;
/**
* Create new service
*/
public IRCService() {
super();
this.connections = new HashMap<Integer, IRCConnection>();
this.binder = new IRCBinder(this);
this.connectedServerTitles = new ArrayList<String>();
this.mentions = new LinkedHashMap<String, Conversation>();
reconnectNextNetwork = new ArrayList<Integer>();
}
private boolean _isTransient = false;
public boolean isNetworkTransient() {
Log.d("IRCService", "Network is transient: " + _isTransient);
return _isTransient;
}
protected synchronized void networksChanged(int newNetworkType) {
// If new network is -1, we need to configure reconnecting.
_isTransient = true;
if( newNetworkType == -1 && settings.reconnectLoss() ) {
updateNotification(getString(R.string.notification_not_connected), "Waiting for network", Notification.PRIORITY_LOW, false, false, false);
reconnectNextNetwork.clear();
for( int sid : connections.keySet() ) {
reconnectNextNetwork.add(sid);
Intent sIntent = Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, sid);
sendBroadcast(sIntent);
}
} else {
// We're changing between networks, not losing our network entirely.
if( settings.reconnectTransient() ) {
updateNotification(getString(R.string.notification_not_connected), "Network in transition", Notification.PRIORITY_LOW, false, false, false);
for( int sid : connections.keySet() ) {
connections.get(sid).disconnect(); // Disconnect and clean up.
if( !reconnectNextNetwork.contains(sid) )
reconnectNextNetwork.add(sid);
}
}
final Integer[] new_servers = (Integer[])reconnectNextNetwork.toArray(new Integer[reconnectNextNetwork.size()]);
for( int reconnect_server : new_servers ) {
Server s = Atomic.getInstance().getServerById(reconnect_server);
this.getConnection(reconnect_server).disconnect();
s.setStatus(Status.PRE_CONNECTING);
Intent sIntent = Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, reconnect_server);
sendBroadcast(sIntent);
Message message = new Message("Waiting on network connectivity");
message.setIcon(R.drawable.info);
message.setColor(MessageColor.SERVER_EVENT);
s.getConversation(ServerInfo.DEFAULT_NAME).addMessage(message);
Intent cIntent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
reconnect_server,
ServerInfo.DEFAULT_NAME
);
sendBroadcast(cIntent);
connect(s);
reconnectNextNetwork.remove((Object)reconnect_server);
}
reconnectNextNetwork.clear();
}
checkServiceStatus();
}
public synchronized void removeReconnection(int sid) {
if( !reconnectNextNetwork.contains(sid) ) {
return; // This server doesn't currently have a reconnect listing.
}
reconnectNextNetwork.remove(reconnectNextNetwork.indexOf(sid));
}
public synchronized void clearReconnectList() {
reconnectNextNetwork.clear();
}
public synchronized boolean isReconnecting(int sid) {
return reconnectNextNetwork.contains(sid);
}
/**
* On create
*/
@Override
public void onCreate() {
super.onCreate();
_netTransitionHandler = new NetworkTransitionHandler(this);
settings = new Settings(getBaseContext());
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature);
} catch ( NoSuchMethodException e ) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
// Load servers from Database
Database db = new Database(this);
Atomic.getInstance().setServers(db.getServers());
db.close();
// Broadcast changed server list
sendBroadcast(new Intent(Broadcast.SERVER_UPDATE));
// Set up our connectivity handler
registerReceiver(_netTransitionHandler, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
/**
* Get Settings object
*
* @return the settings helper object
*/
public Settings getSettings() {
return settings;
}
/**
* On start (will be called on pre-2.0 platform. On 2.0 or later onStartCommand()
* will be called)
*/
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
handleCommand(intent);
}
/**
* On start command (Android >= 2.0)
*
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if( intent != null ) {
handleCommand(intent);
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
//return START_STICKY;
return 1;
}
/**
* Handle command
*
* @param intent
*/
private void handleCommand(Intent intent) {
if( ACTION_FOREGROUND.equals(intent.getAction()) ) {
if( foreground ) {
return; // XXX: We are already in foreground...
}
foreground = true;
Intent notifyIntent = new Intent(this, ServersActivity.class);
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
// Set the icon, scrolling text and timestamp
// now using NotificationCompat for Linter happiness
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_service_icon)
.setWhen(System.currentTimeMillis())
.setContentText(getText(R.string.notification_running))
.setTicker(getText(R.string.notification_not_connected))
.setContentTitle(getText(R.string.app_name))
.setContentIntent(contentIntent)
.setPriority(Notification.PRIORITY_MIN)
.build();
startForegroundCompat(FOREGROUND_NOTIFICATION, notification);
} else if( ACTION_BACKGROUND.equals(intent.getAction()) && !foreground ) {
stopForegroundCompat(FOREGROUND_NOTIFICATION);
} else if( ACTION_ACK_NEW_MENTIONS.equals(intent.getAction()) ) {
ackNewMentions(intent.getIntExtra(EXTRA_ACK_SERVERID, -1), intent.getStringExtra(EXTRA_ACK_CONVTITLE));
}
}
/**
* Update notification and vibrate and/or flash a LED light if needed
*
* @param text The ticker text to display
* @param contentText The text to display in the notification dropdown
* If null, this makes the notification update to be the connection status.
* @param vibrate True if the device should vibrate, false otherwise
* @param sound True if the device should make sound, false otherwise
* @param light True if the device should flash a LED light, false otherwise
*/
private void updateNotification(String text, String contentText, int priority, boolean vibrate, boolean sound, boolean light) {
if( foreground ) {
// NotificationCompat does the right things for ICS
// and other various variants. Seriously, Google?
NotificationCompat.Builder notificationB = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_service_icon)
.setWhen(System.currentTimeMillis())
.setPriority(priority);
Intent notifyIntent = new Intent(this, ServersActivity.class);
// If contentText is null, there's nothing to show
// However, if it isn't null, display that.
if( contentText == null ) {
if( newMentions >= 1 ) {
StringBuilder sb = new StringBuilder();
for( Conversation conv : mentions.values() ) {
sb.append(conv.getName() + " (" + conv.getNewMentions() + "), ");
}
contentText = getString(R.string.notification_mentions,
sb.substring(0, sb.length() - 2));
// We're going to work through the mentions keys. The first half is
// the server ID, the other half
// is the channel that the mention belongs to.
int ServerID = -1;
String Convo = "";
String convID = ((String)(mentions.keySet().toArray()[mentions.size() - 1]));
ServerID = Integer
.parseInt(convID.substring(0, convID.indexOf(':')));
Convo = convID.substring(convID.indexOf(':') + 1);
Log.d("IRCService", "Jump target is '" + Convo + "'");
notifyIntent.setClass(this, ConversationActivity.class);
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
notifyIntent.putExtra("serverId", ServerID);
notifyIntent.putExtra(ConversationActivity.EXTRA_TARGET, "" + Convo);
} else {
if( !connectedServerTitles.isEmpty() ) {
StringBuilder sb = new StringBuilder();
notificationB.setPriority(Notification.PRIORITY_MIN);
for( String title : connectedServerTitles ) {
sb.append(title + ", ");
}
contentText = getString(R.string.notification_connected,
sb.substring(0, sb.length() - 2));
} else {
contentText = getString(R.string.notification_not_connected);
}
}
}
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationB.setContentIntent(contentIntent);
notificationB.setContentTitle(getText(R.string.app_name));
notificationB.setOngoing(false);
notificationB.setNumber(newMentions);
NotificationCompat.Builder publicBuilder = new NotificationCompat.Builder(this);
publicBuilder.setSmallIcon(R.drawable.ic_service_icon);
publicBuilder.setContentTitle(getText(R.string.app_name));
if(newMentions > 0) {
publicBuilder.setContentText(getString(R.string.notification_mentions, newMentions));
publicBuilder.setNumber(newMentions);
}
notificationB.setPublicVersion(publicBuilder.build());
notificationB.setContentText(contentText);
if( text != null ) {
notificationB.setTicker(text);
}
if(light) {
notificationB.setLights(settings.getHighlightLEDColor(), NOTIFICATION_LED_ON_MS, NOTIFICATION_LED_OFF_MS);
}
if(sound) {
notificationB.setSound(settings.getHighlightSoundLocation());
}
if(vibrate) {
notificationB.setVibrate(new long[] {0, 200, 180, 160, 140, 120, 100});
}
Notification notification = notificationB.build();
notificationManager.notify(FOREGROUND_NOTIFICATION, notification);
}
}
/**
* Generates a string uniquely identifying a conversation.
*/
public String getConversationId(int serverId, String title) {
return "" + serverId + ":" + title;
}
/**
* Notify the service of a new mention (updates the status bar notification)
*
* @param conversation The conversation where the new mention occurred
* @param msg The text of the new message
* @param vibrate Whether the notification should include vibration
* @param sound Whether the notification should include sound
* @param light Whether the notification should include a flashing LED light
*/
public synchronized void addNewMention(int serverId, Conversation conversation, String msg, boolean vibrate, boolean sound, boolean light) {
if( conversation == null ) {
return;
}
conversation.addNewMention();
++newMentions;
String convId = getConversationId(serverId, conversation.getName());
if( !mentions.containsKey(convId) ) {
mentions.put(convId, conversation);
}
msg = MircColors.removeStyleAndColors(msg);
updateNotification(msg, null, Notification.PRIORITY_MAX, vibrate, sound, light);
}
/**
* Notify the service that new mentions have been viewed (updates the status bar notification)
*
* @param convTitle The title of the conversation whose new mentions have been read
*/
public synchronized void ackNewMentions(int serverId, String convTitle) {
if( convTitle == null ) {
return;
}
Conversation conversation = mentions.remove(getConversationId(serverId, convTitle));
if( conversation == null ) {
return;
}
newMentions -= conversation.getNewMentions();
conversation.clearNewMentions();
if( newMentions < 0 ) {
newMentions = 0;
}
updateNotification(null, null, Notification.PRIORITY_MIN, false, false, false);
}
/**
* Notify the service of connection to a server (updates the status bar notification)
*
* @param title The title of the newly connected server
*/
public synchronized void notifyConnected(String title) {
connectedServerTitles.add(title);
updateNotification(getString(R.string.notification_connected, title), null, Notification.PRIORITY_HIGH, false, false, false);
}
/**
* Notify the service of disconnection from a server (updates the status bar notification)
*
* @param title The title of the disconnected server
*/
public synchronized void notifyDisconnected(String title) {
connectedServerTitles.remove(title);
updateNotification(getString(R.string.notification_disconnected, title), null,Notification.PRIORITY_DEFAULT, false, false, false);
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
private void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if( mStartForeground != null ) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch ( InvocationTargetException e ) {
// Should not happen.
} catch ( IllegalAccessException e ) {
// Should not happen.
}
} else {
// Fall back on the old API.
try {
Method setForeground = getClass().getMethod("setForeground", mSetForegroudSignaure);
setForeground.invoke(this, new Object[]{true});
} catch ( NoSuchMethodException exception ) {
// Should not happen
} catch ( InvocationTargetException e ) {
// Should not happen.
} catch ( IllegalAccessException e ) {
// Should not happen.
}
notificationManager.notify(id, notification);
}
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
public void stopForegroundCompat(int id) {
foreground = false;
// If we have the new stopForeground API, then use it.
if( mStopForeground != null ) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch ( InvocationTargetException e ) {
// Should not happen.
} catch ( IllegalAccessException e ) {
// Should not happen.
}
} else {
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
notificationManager.cancel(id);
try {
Method setForeground = getClass().getMethod("setForeground", mSetForegroudSignaure);
setForeground.invoke(this, new Object[]{true});
} catch ( NoSuchMethodException exception ) {
// Should not happen
} catch ( InvocationTargetException e ) {
// Should not happen.
} catch ( IllegalAccessException e ) {
// Should not happen.
}
}
}
/**
* Connect to the given server
*/
public void connect(final Server server) {
final int serverId = server.getId();
final IRCService service = this;
if( settings.isReconnectEnabled() ) {
server.setMayReconnect(true);
}
new Thread("Connect thread for " + server.getTitle()) {
@Override
public void run() {
if( settings.isReconnectEnabled() && !server.mayReconnect() ) {
return;
}
try {
I_AM_A_HORRIBLE_BASTARD:
;
IRCConnection connection = getConnection(serverId);
connection.setNickname(server.getIdentity().getNickname());
connection.setAliases(server.getIdentity().getAliases());
connection.setIdent(server.getIdentity().getIdent());
connection.setRealName(server.getIdentity().getRealName());
connection.setUseSSL(server.useSSL());
X509TrustManager[] trustMgr = MemorizingTrustManager.getInstanceList(getApplicationContext());
connection.setTrustManagers(trustMgr);
if( server.getCharset() != null ) {
connection.setEncoding(server.getCharset());
}
if( server.getAuthentication().hasSaslCredentials() ) {
connection.setSaslCredentials(
server.getAuthentication().getSaslUsername(),
server.getAuthentication().getSaslPassword()
);
}
if( server.getPassword() != "" ) {
connection.connect(server.getHost(), server.getPort(), server.getPassword());
} else {
connection.connect(server.getHost(), server.getPort());
}
} catch ( Exception e ) {
server.setStatus(Status.DISCONNECTED);
NetworkInfo ninf = ((ConnectivityManager)(IRCService.this.getSystemService(Service.CONNECTIVITY_SERVICE))).getActiveNetworkInfo();
if( ninf == null ) {
_isTransient = false;
} else {
_isTransient = !(ninf.getState() == NetworkInfo.State.CONNECTED);
}
Intent sIntent = Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, serverId);
sendBroadcast(sIntent);
final IRCConnection connection = getConnection(serverId);
Message message;
if( e instanceof NickAlreadyInUseException ) {
message = new Message(getString(R.string.nickname_in_use, connection.getNick()));
server.setMayReconnect(false);
} else if( e instanceof IrcException ) {
message = new Message(getString(R.string.irc_login_error, server.getHost(), server.getPort()));
server.setMayReconnect(false);
} else if( e instanceof SSLException ) {
// This happens when we declined the SSL certificate most of the time
// We should check what really happened.
message = new Message("SSL negotiation failed: " + e.toString());
} else {
message = new Message(getString(R.string.could_not_connect, server.getHost(), server.getPort()) + ":\n" + e.toString());
if( settings.isReconnectEnabled() ) {
updateNotification("Reconnecting.", "Reconnection queued", Notification.PRIORITY_MIN, false, false, false);
server.setStatus(Status.RECONNECTING);
IRCService.this.sendBroadcast(Broadcast.createServerIntent(
Broadcast.SERVER_UPDATE, serverId));
if( _isTransient && (settings.reconnectTransient() || settings.reconnectLoss()) ) {
reconnectNextNetwork.add(serverId);
message = new Message(
"Connection will be established once network is connected");
} else {
message = new Message("Reconnecting to server... ");
Runnable r = new Runnable() {
@Override
public void run() {
Log.d("IRCService", "In reconnect thread!");
connection.disconnect();
try {
Thread.sleep(5000);
} catch ( Exception eee ) {
;
;
}
if( server.getStatus() != Status.DISCONNECTED ) {
connect(server);
}
}
};
(new Thread(r)).run();
}
}
}
message.setColor(Message.MessageColor.ERROR);
message.setIcon(R.drawable.error);
server.getConversation(ServerInfo.DEFAULT_NAME).addMessage(message);
Intent cIntent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
serverId,
ServerInfo.DEFAULT_NAME
);
sendBroadcast(cIntent);
}
}
}.start();
}
private void runRunnable(Runnable r) {
(new Handler()).post(r);
}
/**
* Get connection for given server
*
* @param serverId
* @return
*/
public synchronized IRCConnection getConnection(int serverId) {
IRCConnection connection = connections.get(serverId);
if( connection == null ) {
connection = new IRCConnection(this, serverId);
connections.put(serverId, connection);
}
return connection;
}
/**
* Does the service keep a connection object for this server?
*
* @return true if there's a connection object, false otherwise
*/
public boolean hasConnection(int serverId) {
return connections.containsKey(serverId);
}
/**
* Check status of service
*/
public void checkServiceStatus() {
boolean shutDown = true;
ArrayList<Server> mServers = Atomic.getInstance().getServersAsArrayList();
int mSize = mServers.size();
Server server;
for( int i = 0; i < mSize; i++ ) {
server = mServers.get(i);
if( server.isDisconnected() && !server.mayReconnect() ) {
int serverId = server.getId();
synchronized (this) {
IRCConnection connection = connections.get(serverId);
if( connection != null ) {
connection.dispose();
}
connections.remove(serverId);
}
} else {
shutDown = false;
}
}
if( shutDown ) {
foreground = false;
stopForegroundCompat(R.string.app_name);
stopSelf();
}
}
/**
* On Destroy
*/
@Override
public void onDestroy() {
// Make sure our notification is gone.
if( foreground ) {
stopForegroundCompat(R.string.app_name);
}
unregisterReceiver(_netTransitionHandler);
}
/**
* On Activity binding to this service
*
* @param intent
* @return
*/
@Override
public IRCBinder onBind(Intent intent) {
return binder;
}
}