PresenceManager.java

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