PresenceManager.java

  1package eu.siacs.conversations.xmpp.manager;
  2
  3import android.util.Log;
  4import com.google.common.base.Strings;
  5import eu.siacs.conversations.AppSettings;
  6import eu.siacs.conversations.Config;
  7import eu.siacs.conversations.android.Device;
  8import eu.siacs.conversations.generator.AbstractGenerator;
  9import eu.siacs.conversations.services.XmppConnectionService;
 10import eu.siacs.conversations.xml.Namespace;
 11import eu.siacs.conversations.xmpp.Jid;
 12import eu.siacs.conversations.xmpp.XmppConnection;
 13import im.conversations.android.xmpp.EntityCapabilities;
 14import im.conversations.android.xmpp.EntityCapabilities2;
 15import im.conversations.android.xmpp.ServiceDescription;
 16import im.conversations.android.xmpp.model.Extension;
 17import im.conversations.android.xmpp.model.capabilties.Capabilities;
 18import im.conversations.android.xmpp.model.capabilties.LegacyCapabilities;
 19import im.conversations.android.xmpp.model.nick.Nick;
 20import im.conversations.android.xmpp.model.pars.PreAuth;
 21import im.conversations.android.xmpp.model.pgp.Signed;
 22import im.conversations.android.xmpp.model.stanza.Presence;
 23import java.util.HashMap;
 24import java.util.Map;
 25
 26public class PresenceManager extends AbstractManager {
 27
 28    private final XmppConnectionService service;
 29    private final AppSettings appSettings;
 30
 31    private final Map<EntityCapabilities.Hash, ServiceDescription> serviceDescriptions =
 32            new HashMap<>();
 33
 34    public PresenceManager(final XmppConnectionService service, final XmppConnection connection) {
 35        super(service.getApplicationContext(), connection);
 36        this.appSettings = new AppSettings(service.getApplicationContext());
 37        this.service = service;
 38    }
 39
 40    public void subscribe(final Jid address) {
 41        subscribe(address, null);
 42    }
 43
 44    public void subscribe(final Jid address, final String preAuth) {
 45
 46        var presence = new Presence(Presence.Type.SUBSCRIBE);
 47        presence.setTo(address);
 48
 49        final var displayName = getAccount().getDisplayName();
 50        if (!Strings.isNullOrEmpty(displayName)) {
 51            presence.addExtension(new Nick(displayName));
 52        }
 53        if (preAuth != null) {
 54            presence.addExtension(new PreAuth()).setToken(preAuth);
 55        }
 56        this.connection.sendPresencePacket(presence);
 57    }
 58
 59    public void unsubscribe(final Jid address) {
 60        var presence = new Presence(Presence.Type.UNSUBSCRIBE);
 61        presence.setTo(address);
 62        this.connection.sendPresencePacket(presence);
 63    }
 64
 65    public void unsubscribed(final Jid address) {
 66        var presence = new Presence(Presence.Type.UNSUBSCRIBED);
 67        presence.setTo(address);
 68        this.connection.sendPresencePacket(presence);
 69    }
 70
 71    public void subscribed(final Jid address) {
 72        var presence = new Presence(Presence.Type.SUBSCRIBED);
 73        presence.setTo(address);
 74        this.connection.sendPresencePacket(presence);
 75    }
 76
 77    public void available() {
 78        available(service.checkListeners() && appSettings.isBroadcastLastActivity());
 79    }
 80
 81    public void available(final boolean withIdle) {
 82        final var account = connection.getAccount();
 83        final var serviceDiscoveryFeatures = getManager(DiscoManager.class).getServiceDescription();
 84        final var infoQuery = serviceDiscoveryFeatures.asInfoQuery();
 85        final var capsHash = EntityCapabilities.hash(infoQuery);
 86        final var caps2Hash = EntityCapabilities2.hash(infoQuery);
 87        serviceDescriptions.put(capsHash, serviceDiscoveryFeatures);
 88        serviceDescriptions.put(caps2Hash, serviceDiscoveryFeatures);
 89        final var capabilities = new Capabilities();
 90        capabilities.setHash(caps2Hash);
 91        final var legacyCapabilities = new LegacyCapabilities();
 92        legacyCapabilities.setNode(DiscoManager.CAPABILITY_NODE);
 93        legacyCapabilities.setHash(capsHash);
 94        final var presence = new Presence();
 95        presence.addExtension(capabilities);
 96        presence.addExtension(legacyCapabilities);
 97        final String pgpSignature = account.getPgpSignature();
 98        final String message = account.getPresenceStatusMessage();
 99        final Presence.Availability availability;
100        if (appSettings.isUserManagedAvailability()) {
101            availability = account.getPresenceStatus();
102        } else {
103            availability = getTargetPresence();
104        }
105        presence.setAvailability(availability);
106        presence.setStatus(message);
107        if (pgpSignature != null) {
108            final var signed = new Signed();
109            signed.setContent(pgpSignature);
110            presence.addExtension(signed);
111        }
112
113        final var lastActivity = service.getLastActivity();
114        if (lastActivity > 0 && withIdle) {
115            final long since =
116                    Math.min(lastActivity, System.currentTimeMillis()); // don't send future dates
117            presence.addChild("idle", Namespace.IDLE)
118                    .setAttribute("since", AbstractGenerator.getTimestamp(since));
119        }
120        Log.d(Config.LOGTAG, "--> " + presence);
121        connection.sendPresencePacket(presence);
122    }
123
124    public void unavailable() {
125        var presence = new Presence(Presence.Type.UNAVAILABLE);
126        this.connection.sendPresencePacket(presence);
127    }
128
129    public void available(final Jid to, final Extension... extensions) {
130        final var presence = new Presence();
131        presence.setTo(to);
132        for (final var extension : extensions) {
133            presence.addExtension(extension);
134        }
135        connection.sendPresencePacket(presence);
136    }
137
138    public void unavailable(final Jid to) {
139        final var presence = new Presence(Presence.Type.UNAVAILABLE);
140        presence.setTo(to);
141        connection.sendPresencePacket(presence);
142    }
143
144    private im.conversations.android.xmpp.model.stanza.Presence.Availability getTargetPresence() {
145        final var device = new Device(context);
146        if (appSettings.isDndOnSilentMode()
147                && device.isPhoneSilenced(appSettings.isTreatVibrateAsSilent())) {
148            return im.conversations.android.xmpp.model.stanza.Presence.Availability.DND;
149        } else if (appSettings.isAwayWhenScreenLocked() && device.isScreenLocked()) {
150            return im.conversations.android.xmpp.model.stanza.Presence.Availability.AWAY;
151        } else {
152            return im.conversations.android.xmpp.model.stanza.Presence.Availability.ONLINE;
153        }
154    }
155
156    public Presence getPresence(final Presence.Availability availability, final boolean personal) {
157        final var account = connection.getAccount();
158        final var serviceDiscoveryFeatures = getManager(DiscoManager.class).getServiceDescription();
159        final var infoQuery = serviceDiscoveryFeatures.asInfoQuery();
160        final var capsHash = EntityCapabilities.hash(infoQuery);
161        final var caps2Hash = EntityCapabilities2.hash(infoQuery);
162        serviceDescriptions.put(capsHash, serviceDiscoveryFeatures);
163        serviceDescriptions.put(caps2Hash, serviceDiscoveryFeatures);
164        final var capabilities = new Capabilities();
165        capabilities.setHash(caps2Hash);
166        final var legacyCapabilities = new LegacyCapabilities();
167        legacyCapabilities.setNode(DiscoManager.CAPABILITY_NODE);
168        legacyCapabilities.setHash(capsHash);
169        final var presence = new Presence();
170        presence.addExtension(capabilities);
171        presence.addExtension(legacyCapabilities);
172
173        if (personal) {
174            final String pgpSignature = account.getPgpSignature();
175            final String message = account.getPresenceStatusMessage();
176            presence.setAvailability(availability);
177            presence.setStatus(message);
178            if (pgpSignature != null) {
179                final var signed = new Signed();
180                signed.setContent(pgpSignature);
181                presence.addExtension(new Signed());
182            }
183        }
184        return presence;
185    }
186
187    public ServiceDescription getCachedServiceDescription(final EntityCapabilities.Hash hash) {
188        return this.serviceDescriptions.get(hash);
189    }
190}