Detailed changes
@@ -3610,6 +3610,7 @@ public class XmppConnectionService extends Service {
return;
}
}
+ // TODO use PingManager
final Jid self = conversation.getMucOptions().getSelf().getFullJid();
final Iq ping = new Iq(Iq.Type.GET);
ping.setTo(self);
@@ -78,6 +78,7 @@ import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.XmppConnection.Features;
import eu.siacs.conversations.xmpp.forms.Data;
+import eu.siacs.conversations.xmpp.manager.CarbonsManager;
import eu.siacs.conversations.xmpp.pep.Avatar;
import im.conversations.android.xmpp.model.stanza.Presence;
import java.util.Arrays;
@@ -1226,7 +1227,8 @@ public class EditAccountActivity extends OmemoActivity
this.binding.accountRegisterNew.setVisibility(View.GONE);
}
if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) {
- final Features features = this.mAccount.getXmppConnection().getFeatures();
+ final var connection = this.mAccount.getXmppConnection();
+ final Features features = connection.getFeatures();
this.binding.stats.setVisibility(View.VISIBLE);
boolean showBatteryWarning = isOptimizingBattery();
boolean showDataSaverWarning = isAffectedByDataSaver();
@@ -1239,7 +1241,7 @@ public class EditAccountActivity extends OmemoActivity
} else {
this.binding.serverInfoRosterVersion.setText(R.string.server_info_unavailable);
}
- if (features.carbons()) {
+ if (connection.getManager(CarbonsManager.class).isEnabled()) {
this.binding.serverInfoCarbons.setText(R.string.server_info_available);
} else {
this.binding.serverInfoCarbons.setText(R.string.server_info_unavailable);
@@ -4,7 +4,9 @@ import android.content.Context;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableClassToInstanceMap;
import eu.siacs.conversations.xmpp.manager.AbstractManager;
+import eu.siacs.conversations.xmpp.manager.CarbonsManager;
import eu.siacs.conversations.xmpp.manager.DiscoManager;
+import eu.siacs.conversations.xmpp.manager.PingManager;
import eu.siacs.conversations.xmpp.manager.PresenceManager;
public class Managers {
@@ -16,7 +18,9 @@ public class Managers {
public static ClassToInstanceMap<AbstractManager> get(
final Context context, final XmppConnection connection) {
return new ImmutableClassToInstanceMap.Builder<AbstractManager>()
+ .put(CarbonsManager.class, new CarbonsManager(context, connection))
.put(DiscoManager.class, new DiscoManager(context, connection))
+ .put(PingManager.class, new PingManager(context, connection))
.put(PresenceManager.class, new PresenceManager(context, connection))
.build();
}
@@ -72,7 +72,9 @@ import eu.siacs.conversations.xmpp.bind.Bind2;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived;
import eu.siacs.conversations.xmpp.manager.AbstractManager;
+import eu.siacs.conversations.xmpp.manager.CarbonsManager;
import eu.siacs.conversations.xmpp.manager.DiscoManager;
+import eu.siacs.conversations.xmpp.manager.PingManager;
import im.conversations.android.xmpp.Entity;
import im.conversations.android.xmpp.model.AuthenticationFailure;
import im.conversations.android.xmpp.model.AuthenticationRequest;
@@ -895,7 +897,6 @@ public class XmppConnection implements Runnable {
Config.LOGTAG,
account.getJid().asBareJid()
+ ": successfully enabled carbons (via Bind 2.0)");
- features.carbonsEnabled = true;
} else if (currentLoginInfo.inlineBindFeatures != null
&& currentLoginInfo.inlineBindFeatures.contains(Namespace.CARBONS)) {
negotiatedCarbons = true;
@@ -903,7 +904,6 @@ public class XmppConnection implements Runnable {
Config.LOGTAG,
account.getJid().asBareJid()
+ ": successfully enabled carbons (via Bind 2.0/implicit)");
- features.carbonsEnabled = true;
} else {
negotiatedCarbons = false;
}
@@ -2175,7 +2175,7 @@ public class XmppConnection implements Runnable {
private void sendPostBindInitialization(
final boolean waitForDisco, final boolean carbonsEnabled) {
- features.carbonsEnabled = carbonsEnabled;
+ getManager(CarbonsManager.class).setEnabledOnBind(carbonsEnabled);
features.blockListRequested = false;
getManager(DiscoManager.class).clear();
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": starting service discovery");
@@ -2365,35 +2365,15 @@ public class XmppConnection implements Runnable {
advancedStreamFeaturesLoadedListeners) {
listener.onAdvancedStreamFeaturesAvailable(account);
}
- if (getFeatures().carbons() && !features.carbonsEnabled) {
- sendEnableCarbons();
+ final var carbonsManager = getManager(CarbonsManager.class);
+ if (carbonsManager.hasFeature() && !carbonsManager.isEnabled()) {
+ carbonsManager.enable();
}
if (getFeatures().commands()) {
discoverCommands();
}
}
- private void sendEnableCarbons() {
- final Iq iq = new Iq(Iq.Type.SET);
- iq.addChild("enable", Namespace.CARBONS);
- this.sendIqPacket(
- iq,
- (packet) -> {
- if (packet.getType() == Iq.Type.RESULT) {
- Log.d(
- Config.LOGTAG,
- account.getJid().asBareJid() + ": successfully enabled carbons");
- features.carbonsEnabled = true;
- } else {
- Log.d(
- Config.LOGTAG,
- account.getJid().asBareJid()
- + ": could not enable carbons "
- + packet);
- }
- });
- }
-
private void processStreamError(final StreamError streamError) throws IOException {
final var loginInfo = this.loginInfo;
final var isSecureLoggedIn = isSecure() && LoginInfo.isSuccess(loginInfo);
@@ -2525,6 +2505,10 @@ public class XmppConnection implements Runnable {
return String.format("%s.%s", BuildConfig.APP_NAME, CryptoHelper.random(3));
}
+ public void sendRequestStanza() {
+ this.sendPacket(new Request());
+ }
+
public ListenableFuture<Iq> sendIqPacket(final Iq request) {
final SettableFuture<Iq> settable = SettableFuture.create();
this.sendIqPacket(
@@ -2654,12 +2638,7 @@ public class XmppConnection implements Runnable {
}
public void sendPing() {
- if (!r()) {
- final Iq iq = new Iq(Iq.Type.GET);
- iq.setFrom(account.getJid());
- iq.addChild("ping", Namespace.PING);
- this.sendIqPacket(iq, null);
- }
+ this.getManager(PingManager.class).ping();
this.lastPingSent = SystemClock.elapsedRealtime();
}
@@ -2873,17 +2852,16 @@ public class XmppConnection implements Runnable {
public void trackOfflineMessageRetrieval(boolean trackOfflineMessageRetrieval) {
if (trackOfflineMessageRetrieval) {
- final Iq iqPing = new Iq(Iq.Type.GET);
- iqPing.addChild("ping", Namespace.PING);
- this.sendIqPacket(
- iqPing,
- (response) -> {
- Log.d(
- Config.LOGTAG,
- account.getJid().asBareJid()
- + ": got ping response after sending initial presence");
- XmppConnection.this.offlineMessagesRetrieved = true;
- });
+ getManager(PingManager.class)
+ .ping(
+ () -> {
+ Log.d(
+ Config.LOGTAG,
+ account.getJid().asBareJid()
+ + ": got ping response after sending initial"
+ + " presence");
+ this.offlineMessagesRetrieved = true;
+ });
} else {
this.offlineMessagesRetrieved = true;
}
@@ -2927,6 +2905,10 @@ public class XmppConnection implements Runnable {
return this.account;
}
+ public Features getStreamFeatures() {
+ return this.features;
+ }
+
private class MyKeyManager implements X509KeyManager {
@Override
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
@@ -3074,8 +3056,9 @@ public class XmppConnection implements Runnable {
}
public class Features {
- XmppConnection connection;
- private boolean carbonsEnabled = false;
+ private final XmppConnection connection;
+
+ // TODO move these three into their respective managers or into XmppConnection
private boolean encryptionEnabled = false;
private boolean blockListRequested = false;
@@ -3088,10 +3071,6 @@ public class XmppConnection implements Runnable {
return infoQuery != null && infoQuery.getFeatureStrings().contains(feature);
}
- public boolean carbons() {
- return hasDiscoFeature(account.getDomain(), Namespace.CARBONS);
- }
-
public boolean commands() {
return hasDiscoFeature(account.getDomain(), Namespace.COMMANDS);
}
@@ -0,0 +1,61 @@
+package eu.siacs.conversations.xmpp.manager;
+
+import android.content.Context;
+import android.util.Log;
+import androidx.annotation.NonNull;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.xml.Namespace;
+import eu.siacs.conversations.xmpp.XmppConnection;
+import im.conversations.android.xmpp.model.carbons.Enable;
+import im.conversations.android.xmpp.model.stanza.Iq;
+
+public class CarbonsManager extends AbstractManager {
+
+ private boolean enabled = false;
+
+ public CarbonsManager(final Context context, final XmppConnection connection) {
+ super(context, connection);
+ }
+
+ public void setEnabledOnBind(final boolean enabledOnBind) {
+ this.enabled = enabledOnBind;
+ }
+
+ public void enable() {
+ final var request = new Iq(Iq.Type.SET);
+ request.addExtension(new Enable());
+ final var future = this.connection.sendIqPacket(request);
+ Futures.addCallback(
+ future,
+ new FutureCallback<>() {
+ @Override
+ public void onSuccess(final Iq result) {
+ CarbonsManager.this.enabled = true;
+ Log.d(
+ Config.LOGTAG,
+ getAccount().getJid().asBareJid()
+ + ": successfully enabled carbons");
+ }
+
+ @Override
+ public void onFailure(@NonNull final Throwable throwable) {
+ Log.d(
+ Config.LOGTAG,
+ getAccount().getJid().asBareJid() + ": could not enable carbons",
+ throwable);
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public boolean hasFeature() {
+ return getManager(DiscoManager.class).hasServerFeature(Namespace.CARBONS);
+ }
+}
@@ -422,6 +422,11 @@ public class DiscoManager extends AbstractManager {
return builder.buildKeepingLast();
}
+ public boolean hasServerFeature(final String feature) {
+ final var infoQuery = this.get(getAccount().getDomain());
+ return infoQuery != null && infoQuery.hasFeature(feature);
+ }
+
private void put(final Jid address, final InfoQuery infoQuery) {
synchronized (this.entityInformation) {
this.entityInformation.put(address, infoQuery);
@@ -0,0 +1,47 @@
+package eu.siacs.conversations.xmpp.manager;
+
+import android.content.Context;
+import androidx.annotation.NonNull;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
+import eu.siacs.conversations.xmpp.XmppConnection;
+import im.conversations.android.xmpp.model.ping.Ping;
+import im.conversations.android.xmpp.model.stanza.Iq;
+import java.util.concurrent.TimeoutException;
+
+public class PingManager extends AbstractManager {
+
+ public PingManager(final Context context, final XmppConnection connection) {
+ super(context, connection);
+ }
+
+ public void ping() {
+ if (connection.getStreamFeatures().sm()) {
+ this.connection.sendRequestStanza();
+ } else {
+ this.connection.sendIqPacket(new Iq(Iq.Type.GET, new Ping()));
+ }
+ }
+
+ public void ping(final Runnable runnable) {
+ final var pingFuture = this.connection.sendIqPacket(new Iq(Iq.Type.GET, new Ping()));
+ Futures.addCallback(
+ pingFuture,
+ new FutureCallback<Iq>() {
+ @Override
+ public void onSuccess(Iq result) {
+ runnable.run();
+ }
+
+ @Override
+ public void onFailure(final @NonNull Throwable t) {
+ if (t instanceof TimeoutException) {
+ return;
+ }
+ runnable.run();
+ }
+ },
+ MoreExecutors.directExecutor());
+ }
+}
@@ -1,12 +1,11 @@
package im.conversations.android.xmpp.model.stanza;
import com.google.common.base.Strings;
-
import eu.siacs.conversations.xml.Element;
-
import im.conversations.android.annotation.XmlElement;
+import im.conversations.android.xmpp.model.Extension;
import im.conversations.android.xmpp.model.error.Error;
-
+import java.util.Arrays;
import java.util.Locale;
@XmlElement
@@ -23,6 +22,11 @@ public class Iq extends Stanza {
this.setAttribute("type", type.toString().toLowerCase(Locale.ROOT));
}
+ public Iq(final Type type, final Extension... extensions) {
+ this(type);
+ this.addExtensions(Arrays.asList(extensions));
+ }
+
// TODO get rid of timeout
public enum Type {
SET,