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

299 lines
11 KiB
Java
Raw Normal View History

2019-05-27 21:34:11 +02:00
package org.mercury_im.messenger.service;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.util.LongSparseArray;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.roster.RosterLoadedListener;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jxmpp.jid.EntityBareJid;
import org.mercury_im.messenger.MercuryImApplication;
import org.mercury_im.messenger.Notifications;
import org.mercury_im.messenger.R;
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.room.AppDatabase;
import org.mercury_im.messenger.persistence.room.model.RoomAccountModel;
import org.mercury_im.messenger.persistence.room.model.RoomContactModel;
import org.mercury_im.messenger.ui.MainActivity;
import org.mercury_im.messenger.xmpp_android.ParcelableXMPPTCPConnectionConfiguration;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
/**
* Started Service, which is responsible for managing {@link XMPPConnection XMPPConnections}
* affiliated with registered accounts.
*/
public class XmppStartedService extends Service {
private static final String TAG = MercuryImApplication.TAG;
private static final String APP = "org.olomono.mercury";
private static final String SERVICE = APP + ".XmppStartedService";
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";
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";
public static final String EVENT_INCOMING_MESSAGE = EVENT + ".INCOMING_MESSAGE";
public static final String EVENT_OUTGOING_MESSAGE = EVENT + ".OUTGOING_MESSAGE";
public static final String EXTRA_CONFIGURATION = EXTRA + ".CONFIGURATION";
public static final String EXTRA_ACCOUNT_ID = EXTRA + ".ACCOUNT_ID";
public static final String STATUS_SUCCESS = STATUS + ".SUCCESS";
public static final String STATUS_FAILURE = STATUS + ".FAILURE";
@Inject
AppDatabase database;
@Inject
ContactRepository rosterRepository;
@Inject
AccountRepository accountRepository;
private final LongSparseArray<XMPPConnection> connections = new LongSparseArray<>();
private Handler uiHandler;
@Nullable
@Override
public final IBinder onBind(Intent intent) {
// We are a started service, so we don't provide a binding and always return null.
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
MercuryImApplication.getApplication().getAppComponent().inject(this);
Intent intent = new Intent(this, XmppBoundService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
XmppBoundService.Binder binder = (XmppBoundService.Binder) iBinder;
XmppBoundService boundService = binder.getService();
boundService.setXmppStartedService(XmppStartedService.this);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (uiHandler == null) {
uiHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
Message m = (Message) msg.obj;
Toast.makeText(XmppStartedService.this, (m.getFrom() != null ? m.getFrom().toString() : "null") + ": "
+ m.getBody(), Toast.LENGTH_LONG).show();
}
}
};
}
Log.d(TAG, "onStartCommand(" + intent + ")");
if (intent == null) {
startAndDisplayForegroundNotification();
} else {
String action = intent.getAction();
action = action == null ? "" : action;
switch (action) {
case ACTION_START:
startAndDisplayForegroundNotification();
startConnections();
break;
case ACTION_STOP:
stopForeground(true);
break;
case ACTION_CONNECT:
ParcelableXMPPTCPConnectionConfiguration configuration = intent.getParcelableExtra(EXTRA_CONFIGURATION);
if (configuration == null) {
Log.e(TAG, "Configuration is null.");
return START_STICKY_COMPATIBILITY;
}
long accountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1);
if (accountId == -1) {
Log.d(TAG, "No AccountID provided.");
return START_STICKY_COMPATIBILITY;
}
new Thread() {
public void run() {
XMPPConnection connection = startConnection(configuration, accountId);
connections.put(accountId, connection);
}
}.start();
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 startConnections() {
new Thread() {
@Override
public void run() {
synchronized (connections) {
List<RoomAccountModel> accounts = accountRepository.getAllAccounts();
if (accounts == null) return;
for (AccountModel a : accounts) {
if (connections.get(a.getId()) != null) {
continue;
}
// XMPPConnection connection = startConnection(a.getJid(), a.getPassword(), a.getId());
// connections.put(a.getId(), connection);
}
}
}
}.start();
}
private XMPPConnection startConnection(ParcelableXMPPTCPConnectionConfiguration connectionConfiguration, long accountId) {
XMPPTCPConnection con = null;
try {
XMPPTCPConnectionConfiguration conf = connectionConfiguration.getConfiguration();
con = new XMPPTCPConnection(conf);
con.connect().login();
} catch (
XMPPException e) {
e.printStackTrace();
} catch (
SmackException e) {
e.printStackTrace();
} catch (
IOException e) {
e.printStackTrace();
} catch (
InterruptedException e) {
e.printStackTrace();
}
NotificationManagerCompat.from(getApplicationContext()).notify(Notifications.FOREGROUND_SERVICE_ID,
getForegroundNotification(getApplicationContext(), connections.size()));
Roster roster = Roster.getInstanceFor(con);
roster.addRosterLoadedListener(new RosterLoadedListener() {
@Override
public void onRosterLoaded(Roster roster) {
Set<RosterEntry> entries = roster.getEntries();
for (RosterEntry e : entries) {
Log.d(TAG, "Inserting Roster entry " + e.getJid().toString());
RoomContactModel m = new RoomContactModel(e.getJid().asEntityBareJidIfPossible(), e.getName(), e.getName());
m.setAccountId(accountId);
rosterRepository.updateOrInsertRosterEntry(m);
}
}
@Override
public void onRosterLoadingFailed(Exception exception) {
Log.d(TAG, "Roster Loading failed", exception);
}
});
try {
roster.reload();
} catch (SmackException.NotLoggedInException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
ChatManager chatManager = ChatManager.getInstanceFor(con);
chatManager.addIncomingListener(new IncomingChatMessageListener() {
@Override
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
android.os.Message msg = uiHandler.obtainMessage(1, message);
msg.sendToTarget();
}
});
return con;
}
public XMPPConnection getConnection(long accountId) {
return connections.get(accountId);
}
public void putConnection(int accountId, XMPPConnection connection) {
connections.put(accountId, connection);
}
}