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            presence.addExtension(new Signed(pgpSignature));
109        }
110
111        final var lastActivity = service.getLastActivity();
112        if (lastActivity > 0 && withIdle) {
113            final long since =
114                    Math.min(lastActivity, System.currentTimeMillis()); // don't send future dates
115            presence.addChild("idle", Namespace.IDLE)
116                    .setAttribute("since", AbstractGenerator.getTimestamp(since));
117        }
118        Log.d(Config.LOGTAG, "--> " + presence);
119        connection.sendPresencePacket(presence);
120    }
121
122    public void unavailable() {
123        var presence = new Presence(Presence.Type.UNAVAILABLE);
124        this.connection.sendPresencePacket(presence);
125    }
126
127    public void available(final Jid to, final Extension... extensions) {
128        available(to, null, extensions);
129    }
130
131    public void available(final Jid to, final String message, final Extension... extensions) {
132        final var presence = new Presence();
133        presence.setTo(to);
134        presence.setStatus(message);
135        for (final var extension : extensions) {
136            presence.addExtension(extension);
137        }
138        connection.sendPresencePacket(presence);
139    }
140
141    public void unavailable(final Jid to) {
142        final var presence = new Presence(Presence.Type.UNAVAILABLE);
143        presence.setTo(to);
144        connection.sendPresencePacket(presence);
145    }
146
147    private im.conversations.android.xmpp.model.stanza.Presence.Availability getTargetPresence() {
148        final var device = new Device(context);
149        if (appSettings.isDndOnSilentMode()
150                && device.isPhoneSilenced(appSettings.isTreatVibrateAsSilent())) {
151            return im.conversations.android.xmpp.model.stanza.Presence.Availability.DND;
152        } else if (appSettings.isAwayWhenScreenLocked() && device.isScreenLocked()) {
153            return im.conversations.android.xmpp.model.stanza.Presence.Availability.AWAY;
154        } else {
155            return im.conversations.android.xmpp.model.stanza.Presence.Availability.ONLINE;
156        }
157    }
158
159    public Presence getPresence(final Presence.Availability availability, final boolean personal) {
160        final var account = connection.getAccount();
161        final var serviceDiscoveryFeatures = getManager(DiscoManager.class).getServiceDescription();
162        final var infoQuery = serviceDiscoveryFeatures.asInfoQuery();
163        final var capsHash = EntityCapabilities.hash(infoQuery);
164        final var caps2Hash = EntityCapabilities2.hash(infoQuery);
165        serviceDescriptions.put(capsHash, serviceDiscoveryFeatures);
166        serviceDescriptions.put(caps2Hash, serviceDiscoveryFeatures);
167        final var capabilities = new Capabilities();
168        capabilities.setHash(caps2Hash);
169        final var legacyCapabilities = new LegacyCapabilities();
170        legacyCapabilities.setNode(DiscoManager.CAPABILITY_NODE);
171        legacyCapabilities.setHash(capsHash);
172        final var presence = new Presence();
173        presence.addExtension(capabilities);
174        presence.addExtension(legacyCapabilities);
175
176        if (personal) {
177            final String pgpSignature = account.getPgpSignature();
178            final String message = account.getPresenceStatusMessage();
179            presence.setAvailability(availability);
180            presence.setStatus(message);
181            if (pgpSignature != null) {
182                final var signed = new Signed();
183                signed.setContent(pgpSignature);
184                presence.addExtension(new Signed());
185            }
186        }
187        return presence;
188    }
189
190    public ServiceDescription getCachedServiceDescription(final EntityCapabilities.Hash hash) {
191        return this.serviceDescriptions.get(hash);
192    }
193}