optional mode to close tcp connection when going into background

Daniel Gultsch created

acts only when push is available. disable all non-push accounts to test properly

Change summary

src/main/java/eu/siacs/conversations/Config.java                         |  2 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 32 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java            | 58 
3 files changed, 63 insertions(+), 29 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/Config.java 🔗

@@ -31,6 +31,8 @@ public final class Config {
 	public static final int CARBON_GRACE_PERIOD = 90;
 	public static final int MINI_GRACE_PERIOD = 750;
 
+	public static final boolean CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND = false;
+
 	public static final int AVATAR_SIZE = 192;
 	public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
 

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -303,7 +303,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 				scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
 			} else if (account.getStatus() == Account.State.OFFLINE) {
 				resetSendingToWaiting(account);
-				if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+				final boolean disabled = account.isOptionSet(Account.OPTION_DISABLED);
+				final boolean pushMode = Config.CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND
+						&& mPushManagementService.available(account)
+						&& checkListeners();
+				Log.d(Config.LOGTAG,account.getJid().toBareJid()+": push mode "+Boolean.toString(pushMode));
+				if (!disabled && !pushMode) {
 					int timeToReconnect = mRandom.nextInt(20) + 10;
 					scheduleWakeUpCall(timeToReconnect, account.getUuid().hashCode());
 				}
@@ -469,6 +474,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		final String action = intent == null ? null : intent.getAction();
 		boolean interactive = false;
 		if (action != null) {
+			Log.d(Config.LOGTAG,"start reason: "+action);
 			switch (action) {
 				case ConnectivityManager.CONNECTIVITY_ACTION:
 					if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) {
@@ -762,18 +768,20 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 						disconnect(account, false);
 					}
 				}).start();
-
+				cancelWakeUpCall(account.getUuid().hashCode());
 			}
 		}
-		Context context = getApplicationContext();
-		AlarmManager alarmManager = (AlarmManager) context
-				.getSystemService(Context.ALARM_SERVICE);
-		Intent intent = new Intent(context, EventReceiver.class);
-		alarmManager.cancel(PendingIntent.getBroadcast(context, 0, intent, 0));
 		Log.d(Config.LOGTAG, "good bye");
 		stopSelf();
 	}
 
+	private void cancelWakeUpCall(int requestCode) {
+		final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+		final Intent intent = new Intent(this, EventReceiver.class);
+		intent.setAction("ping");
+		alarmManager.cancel(PendingIntent.getBroadcast(this, requestCode, intent, 0));
+	}
+
 	public void scheduleWakeUpCall(int seconds, int requestCode) {
 		final long timeToWake = SystemClock.elapsedRealtime() + (seconds < 0 ? 1 : seconds + 1) * 1000;
 
@@ -1719,8 +1727,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 		for (Account account : getAccounts()) {
 			if (account.getStatus() == Account.State.ONLINE) {
 				XmppConnection connection = account.getXmppConnection();
-				if (connection != null && connection.getFeatures().csi()) {
-					connection.sendInactive();
+				if (connection != null) {
+					if (connection.getFeatures().csi()) {
+						connection.sendInactive();
+					}
+					if (Config.CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND && mPushManagementService.available(account)) {
+						connection.waitForPush();
+						cancelWakeUpCall(account.getUuid().hashCode());
+					}
 				}
 			}
 		}

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -61,7 +61,6 @@ import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.ServiceDiscoveryResult;
 import eu.siacs.conversations.generator.IqGenerator;
 import eu.siacs.conversations.services.XmppConnectionService;
-import eu.siacs.conversations.utils.CryptoHelper;
 import eu.siacs.conversations.utils.DNSHelper;
 import eu.siacs.conversations.utils.SSLSocketHelper;
 import eu.siacs.conversations.utils.SocksSocketFactory;
@@ -352,13 +351,7 @@ public class XmppConnection implements Runnable {
 			this.changeStatus(Account.State.OFFLINE);
 			this.attempt--; //don't count attempt when reconnecting instantly anyway
 		} finally {
-			if (socket != null) {
-				try {
-					socket.close();
-				} catch (IOException e) {
-
-				}
-			}
+			forceCloseSocket();
 			if (wakeLock.isHeld()) {
 				try {
 					wakeLock.release();
@@ -430,13 +423,7 @@ public class XmppConnection implements Runnable {
 
 	@Override
 	public void run() {
-		try {
-			if (socket != null) {
-				socket.close();
-			}
-		} catch (final IOException ignored) {
-
-		}
+		forceCloseSocket();
 		connect();
 	}
 
@@ -1283,14 +1270,45 @@ public class XmppConnection implements Runnable {
 		}
 	}
 
-	public void disconnect(final boolean force) {
-		Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force));
-		if (force) {
+	public void waitForPush() {
+		if (tagWriter.isActive()) {
+			tagWriter.finish();
+			new Thread(new Runnable() {
+				@Override
+				public void run() {
+					try {
+						while(!tagWriter.finished()) {
+							Thread.sleep(10);
+						}
+						socket.close();
+						Log.d(Config.LOGTAG,account.getJid().toBareJid()+": closed tcp without closing stream");
+					} catch (IOException e) {
+						e.printStackTrace();
+					} catch (InterruptedException e) {
+						e.printStackTrace();
+					}
+				}
+			}).start();
+		} else {
+			forceCloseSocket();
+			Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": closed tcp without closing stream (no waiting)");
+		}
+	}
+
+	private void forceCloseSocket() {
+		if (socket != null) {
 			try {
 				socket.close();
-			} catch(Exception e) {
-				Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": exception during force close ("+e.getMessage()+")");
+			} catch (IOException e) {
+				e.printStackTrace();
 			}
+		}
+	}
+
+	public void disconnect(final boolean force) {
+		Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force));
+		if (force) {
+			forceCloseSocket();
 			return;
 		} else {
 			if (tagWriter.isActive()) {