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        final var presence = new Presence(Presence.Type.SUBSCRIBE);
 48        presence.setTo(address);
 49
 50        final var displayName = getAccount().getDisplayName();
 51        if (!Strings.isNullOrEmpty(displayName)) {
 52            presence.addExtension(new Nick(displayName));
 53        }
 54        if (preAuth != null) {
 55            presence.addExtension(new PreAuth()).setToken(preAuth);
 56        }
 57        this.connection.sendPresencePacket(presence);
 58    }
 59
 60    public void unsubscribe(final Jid address) {
 61        final var presence = new Presence(Presence.Type.UNSUBSCRIBE);
 62        presence.setTo(address);
 63        this.connection.sendPresencePacket(presence);
 64    }
 65
 66    public void unsubscribed(final Jid address) {
 67        final var presence = new Presence(Presence.Type.UNSUBSCRIBED);
 68        presence.setTo(address);
 69        this.connection.sendPresencePacket(presence);
 70    }
 71
 72    public void subscribed(final Jid address) {
 73        var presence = new Presence(Presence.Type.SUBSCRIBED);
 74        presence.setTo(address);
 75        this.connection.sendPresencePacket(presence);
 76    }
 77
 78    public void available() {
 79        available(service.checkListeners() && appSettings.isBroadcastLastActivity());
 80    }
 81
 82    public void available(final boolean withIdle) {
 83        final var account = connection.getAccount();
 84        final var serviceDiscoveryFeatures = getManager(DiscoManager.class).getServiceDescription();
 85        final var infoQuery = serviceDiscoveryFeatures.asInfoQuery();
 86        final var capsHash = EntityCapabilities.hash(infoQuery);
 87        final var caps2Hash = EntityCapabilities2.hash(infoQuery);
 88        serviceDescriptions.put(capsHash, serviceDiscoveryFeatures);
 89        serviceDescriptions.put(caps2Hash, serviceDiscoveryFeatures);
 90        final var capabilities = new Capabilities();
 91        capabilities.setHash(caps2Hash);
 92        final var legacyCapabilities = new LegacyCapabilities();
 93        legacyCapabilities.setNode(DiscoManager.CAPABILITY_NODE);
 94        legacyCapabilities.setHash(capsHash);
 95        final var presence = new Presence();
 96        presence.addExtension(capabilities);
 97        presence.addExtension(legacyCapabilities);
 98        final String pgpSignature = account.getPgpSignature();
 99        final String message = account.getPresenceStatusMessage();
100        final Presence.Availability availability;
101        if (appSettings.isUserManagedAvailability()) {
102            availability = account.getPresenceStatus();
103        } else {
104            availability = getTargetPresence();
105        }
106        presence.setAvailability(availability);
107        presence.setStatus(message);
108        if (pgpSignature != null) {
109            presence.addExtension(new Signed(pgpSignature));
110        }
111
112        final var lastActivity = service.getLastActivity();
113        if (lastActivity > 0 && withIdle) {
114            final long since =
115                    Math.min(lastActivity, System.currentTimeMillis()); // don't send future dates
116            presence.addChild("idle", Namespace.IDLE)
117                    .setAttribute("since", AbstractGenerator.getTimestamp(since));
118        }
119        Log.d(Config.LOGTAG, "--> " + presence);
120        connection.sendPresencePacket(presence);
121    }
122
123    public void unavailable() {
124        var presence = new Presence(Presence.Type.UNAVAILABLE);
125        this.connection.sendPresencePacket(presence);
126    }
127
128    public void available(final Jid to, final Extension... extensions) {
129        available(to, null, extensions);
130    }
131
132    public void available(final Jid to, final String message, final Extension... extensions) {
133        final var presence = new Presence();
134        presence.setTo(to);
135        presence.setStatus(message);
136        for (final var extension : extensions) {
137            presence.addExtension(extension);
138        }
139        connection.sendPresencePacket(presence);
140    }
141
142    public void unavailable(final Jid to) {
143        final var presence = new Presence(Presence.Type.UNAVAILABLE);
144        presence.setTo(to);
145        connection.sendPresencePacket(presence);
146    }
147
148    private im.conversations.android.xmpp.model.stanza.Presence.Availability getTargetPresence() {
149        final var device = new Device(context);
150        if (appSettings.isDndOnSilentMode()
151                && device.isPhoneSilenced(appSettings.isTreatVibrateAsSilent())) {
152            return im.conversations.android.xmpp.model.stanza.Presence.Availability.DND;
153        } else if (appSettings.isAwayWhenScreenLocked() && device.isScreenLocked()) {
154            return im.conversations.android.xmpp.model.stanza.Presence.Availability.AWAY;
155        } else {
156            return im.conversations.android.xmpp.model.stanza.Presence.Availability.ONLINE;
157        }
158    }
159
160    public ServiceDescription getCachedServiceDescription(final EntityCapabilities.Hash hash) {
161        return this.serviceDescriptions.get(hash);
162    }
163}