Mercury-IM/app/src/main/java/org/mercury_im/messenger/service/XmppConnectionService.java

238 lines
8.4 KiB
Java

package org.mercury_im.messenger.service;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.util.LongSparseArray;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager;
import org.jxmpp.stringprep.XmppStringprepException;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.Notifications;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.handler.RoomPlainMessageHandler;
import org.mercury_im.messenger.handler.RoomRosterHandler;
import org.mercury_im.messenger.persistence.model.AccountModel;
import org.mercury_im.messenger.persistence.repository.AccountRepository;
import org.mercury_im.messenger.persistence.repository.ContactRepository;
import org.mercury_im.messenger.persistence.repository.EntityRepository;
import org.mercury_im.messenger.persistence.room.dao.ContactDao;
import org.mercury_im.messenger.persistence.room.dao.EntityDao;
import org.mercury_im.messenger.ui.MainActivity;
import org.mercury_im.messenger.xmpp_android.AndroidMercuryConnection;
import org.mercury_im.messenger.xmpp_core.ConnectionHolder;
import org.mercury_im.messenger.xmpp_core.MercuryConnection;
import java.io.IOException;
import java.util.List;
import javax.inject.Inject;
/**
* Started, Bound Service, which is responsible for managing {@link XMPPConnection XMPPConnections}
* affiliated with registered accounts.
*/
public class XmppConnectionService extends Service implements ConnectionHolder {
private static final String TAG = MercuryImApplication.TAG;
private static final String APP = "org.mercury-im.messenger";
private static final String SERVICE = APP + ".XmppConnectionService";
private static final String ACTION = SERVICE + ".ACTION";
private static final String EVENT = SERVICE + ".EVENT";
private static final String EXTRA = SERVICE + ".EXTRA";
private static final String STATUS = SERVICE + ".STATUS";
// ACTIONS
public static final String ACTION_START = ACTION + ".START";
public static final String ACTION_STOP = ACTION + ".STOP";
public static final String ACTION_CONNECT = ACTION + ".CONNECT";
public static final String ACTION_DISCONNECT = ACTION + ".DISCONNECT";
public static final String ACTION_PING = ACTION + ".PING";
// EVENTS
public static final String EVENT_INCOMING_MESSAGE = EVENT + ".INCOMING_MESSAGE";
public static final String EVENT_OUTGOING_MESSAGE = EVENT + ".OUTGOING_MESSAGE";
// EXTRAS
public static final String EXTRA_CONFIGURATION = EXTRA + ".CONFIGURATION";
public static final String EXTRA_ACCOUNT_ID = EXTRA + ".ACCOUNT_ID";
// STATUSES
public static final String STATUS_SUCCESS = STATUS + ".SUCCESS";
public static final String STATUS_FAILURE = STATUS + ".FAILURE";
@Inject
ContactRepository contactRepository;
@Inject
AccountRepository accountRepository;
@Inject
EntityRepository entityRepository;
@Inject
EntityDao entityDao;
@Inject
ContactDao contactDao;
private final LongSparseArray<MercuryConnection> connections = new LongSparseArray<>();
private Handler uiHandler;
@NonNull
@Override
public final IBinder onBind(Intent intent) {
return new Binder(this);
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
MercuryImApplication.getApplication().getAppComponent().inject(this);
new Thread() {
@Override
public void run() {
List<AccountModel> accounts = accountRepository.getAllAccounts();
for(AccountModel accountModel : accounts) {
startConnection(accountModel);
}
}
}.start();
// Begin life cycle of Ping Manager.
// The Manager will automatically detect newly created connections and ping the server
// every half hour if necessary.
ServerPingWithAlarmManager.onCreate(this);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
// End life cycle of Ping Manager.
ServerPingWithAlarmManager.onDestroy();
}
@Override
public MercuryConnection getConnection(long accountId) {
return connections.get(accountId);
}
@Override
public void putConnection(long accountId, MercuryConnection connection) {
connections.put(accountId, connection);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand(" + intent + ")");
if (intent == null) {
startAndDisplayForegroundNotification();
} else {
String action = intent.getAction();
action = action == null ? "" : action;
switch (action) {
case ACTION_START:
startAndDisplayForegroundNotification();
break;
case ACTION_STOP:
stopForeground(true);
stopSelf();
break;
default:
break;
}
}
return START_STICKY_COMPATIBILITY;
}
public void startAndDisplayForegroundNotification() {
Log.d(TAG, "startAndDisplayForegroundNotification()");
Notification notification = getForegroundNotification(getApplicationContext(), connections.size());
startForeground(Notifications.FOREGROUND_SERVICE_ID, notification);
}
static Notification getForegroundNotification(Context context, int numConnections) {
Intent startMainActivityIntent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
startMainActivityIntent, 0);
return new NotificationCompat.Builder(context, Notifications.NOTIFICATION_CHANNEL__FOREGROUND_SERVICE)
.setContentTitle("Mercury")
.setContentText(numConnections + " connections.")
.setSmallIcon(R.drawable.ic_send_black_24dp)
.setContentIntent(pendingIntent)
.build();
}
public void startConnection(AccountModel accountModel) {
MercuryConnection connection = connections.get(accountModel.getId());
if (connection != null) {
return;
}
new Thread() {
@Override
public void run() {
try {
XMPPTCPConnection connection = new XMPPTCPConnection(accountModel.getJid().getLocalpart().asUnescapedString(),
accountModel.getPassword(), accountModel.getJid().getDomain().toString());
MercuryConnection mercuryConnection = new AndroidMercuryConnection(connection, accountModel.getId());
putConnection(accountModel.getId(), mercuryConnection);
mercuryConnection.setRosterHandler(new RoomRosterHandler(mercuryConnection));
mercuryConnection.setPlainMessageHandler(new RoomPlainMessageHandler(accountModel.getId()));
connection.connect().login();
Log.d(MercuryImApplication.TAG, "Logged in for " + accountModel.getJid().toString());
} catch (XmppStringprepException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
}
}
}.start();
}
public class Binder extends android.os.Binder {
private final XmppConnectionService service;
public Binder(XmppConnectionService service) {
this.service = service;
}
public XmppConnectionService getService() {
return service;
}
}
}