210 lines
7.3 KiB
Java
210 lines
7.3 KiB
Java
package org.mercury_im.messenger.android.service;
|
|
|
|
import android.app.Notification;
|
|
import android.app.NotificationManager;
|
|
import android.app.PendingIntent;
|
|
import android.app.Service;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.os.IBinder;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.core.app.NotificationCompat;
|
|
|
|
import org.jivesoftware.smackx.ping.android.ServerPingWithAlarmManager;
|
|
import org.mercury_im.messenger.R;
|
|
import org.mercury_im.messenger.android.MercuryImApplication;
|
|
import org.mercury_im.messenger.android.Notifications;
|
|
import org.mercury_im.messenger.android.ui.MainActivity;
|
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
|
import org.mercury_im.messenger.core.connection.state.ConnectionPoolState;
|
|
import org.mercury_im.messenger.core.connection.state.ConnectionState;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.inject.Inject;
|
|
|
|
import io.reactivex.disposables.CompositeDisposable;
|
|
import io.reactivex.disposables.Disposable;
|
|
|
|
/**
|
|
* Started, Bound Service, which is responsible keeping the application alive when the app is not open.
|
|
*/
|
|
public class MercuryForegroundService extends Service {
|
|
|
|
private static final String APP = "org.mercury-im.messenger";
|
|
private static final String SERVICE = APP + ".MercuryForegroundService";
|
|
|
|
private static final String ACTION = SERVICE + ".ACTION";
|
|
|
|
// ACTIONS
|
|
public static final String ACTION_START = ACTION + ".START";
|
|
public static final String ACTION_STOP = ACTION + ".STOP";
|
|
|
|
private static final Logger LOGGER = Logger.getLogger(MercuryForegroundService.class.getName());
|
|
|
|
@Inject
|
|
MercuryConnectionManager connectionManager;
|
|
|
|
CompositeDisposable disposable;
|
|
|
|
@NonNull
|
|
@Override
|
|
public final IBinder onBind(Intent intent) {
|
|
return new Binder(this);
|
|
}
|
|
|
|
@Override
|
|
public void onCreate() {
|
|
super.onCreate();
|
|
MercuryImApplication.getApplication().getAppComponent().inject(this);
|
|
beginLifecycleOfPingManager();
|
|
disposable = new CompositeDisposable();
|
|
disposable.add(connectionManager.observeConnectionPool()
|
|
.subscribe(state -> {
|
|
Notification notification = buildForegroundNotification(getApplicationContext(), state);
|
|
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
notificationManager.notify(Notifications.FOREGROUND_SERVICE_ID, notification);
|
|
}));
|
|
LOGGER.log(Level.INFO, "onCreate");
|
|
}
|
|
|
|
/**
|
|
* PingManager will ensure the XMPP connection is kept alive.
|
|
*/
|
|
private void beginLifecycleOfPingManager() {
|
|
ServerPingWithAlarmManager.onCreate(this);
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
super.onDestroy();
|
|
disposable.dispose();
|
|
endLifecycleOfPingManager();
|
|
LOGGER.log(Level.INFO, "onDestroy");
|
|
}
|
|
|
|
private void endLifecycleOfPingManager() {
|
|
ServerPingWithAlarmManager.onDestroy();
|
|
}
|
|
|
|
@Override
|
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
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;
|
|
}
|
|
|
|
private void startAndDisplayForegroundNotification() {
|
|
Notification notification = buildForegroundNotification(getApplicationContext(),
|
|
connectionManager.observeConnectionPool().blockingFirst());
|
|
startForeground(Notifications.FOREGROUND_SERVICE_ID, notification);
|
|
}
|
|
|
|
private static Notification buildForegroundNotification(Context context, ConnectionPoolState state) {
|
|
Intent startMainActivityIntent = new Intent(context, MainActivity.class);
|
|
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
|
|
startMainActivityIntent, 0);
|
|
|
|
String notificationText = notificationTextFrom(state);
|
|
|
|
return new NotificationCompat.Builder(context, Notifications.NOTIFICATION_CHANNEL__FOREGROUND_SERVICE)
|
|
.setSmallIcon(R.drawable.ic_mercury_black_24dp)
|
|
.setContentTitle("Mercury-IM is running!")
|
|
.setContentText(notificationText)
|
|
.setStyle(new NotificationCompat.BigTextStyle().bigText(notificationText))
|
|
.setContentIntent(pendingIntent)
|
|
.build();
|
|
}
|
|
|
|
private static String notificationTextFrom(ConnectionPoolState state) {
|
|
List<UUID> connecting = new ArrayList<>();
|
|
List<UUID> authenticated = new ArrayList<>();
|
|
List<UUID> erred = new ArrayList<>();
|
|
for (UUID id : state.getConnectionStates().keySet()) {
|
|
ConnectionState connectionState = state.getConnectionStates().get(id);
|
|
switch (connectionState.getConnectivity()) {
|
|
case disconnected:
|
|
break;
|
|
case connecting:
|
|
case connected:
|
|
connecting.add(id);
|
|
break;
|
|
case authenticated:
|
|
authenticated.add(id);
|
|
break;
|
|
case disconnectedOnError:
|
|
erred.add(id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
if (!authenticated.isEmpty()) {
|
|
sb.append(authenticated.size())
|
|
.append(authenticated.size() == 1 ? " account" : " accounts")
|
|
.append(" connected.");
|
|
}
|
|
if (!connecting.isEmpty()) {
|
|
if (!sb.toString().isEmpty()) {
|
|
sb.append("\n");
|
|
}
|
|
sb.append(connecting.size())
|
|
.append(authenticated.size() == 1 ? " account" : " accounts")
|
|
.append(" connecting.");
|
|
}
|
|
if (!erred.isEmpty()) {
|
|
if (!sb.toString().isEmpty()) {
|
|
sb.append("\n");
|
|
}
|
|
Iterator<UUID> iterator = erred.iterator();
|
|
while (iterator.hasNext()) {
|
|
UUID id = iterator.next();
|
|
sb.append(getAddress(state, id));
|
|
if (iterator.hasNext()) sb.append(", ");
|
|
}
|
|
sb.append(erred.size() == 1 ? " has an error." : " have errors.");
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
private static String getAddress(ConnectionPoolState state, UUID uuid) {
|
|
return state.getConnectionStates().get(uuid).getConnection().getAccount().getAddress();
|
|
}
|
|
|
|
public class Binder extends android.os.Binder {
|
|
|
|
private final MercuryForegroundService service;
|
|
|
|
public Binder(MercuryForegroundService service) {
|
|
this.service = service;
|
|
}
|
|
|
|
public MercuryForegroundService getService() {
|
|
return service;
|
|
}
|
|
}
|
|
}
|