Presences.java

  1package eu.siacs.conversations.entities;
  2
  3import android.util.Pair;
  4import com.google.common.base.Strings;
  5import com.google.common.collect.Iterables;
  6import eu.siacs.conversations.xmpp.manager.DiscoManager;
  7import im.conversations.android.xmpp.model.disco.info.Identity;
  8import im.conversations.android.xmpp.model.stanza.Presence;
  9import java.util.ArrayList;
 10import java.util.HashMap;
 11import java.util.HashSet;
 12import java.util.List;
 13import java.util.Map;
 14import java.util.Set;
 15
 16public class Presences {
 17    private final HashMap<String, Presence> presences = new HashMap<>();
 18    private final Contact contact;
 19
 20    public Presences(final Contact contact) {
 21        this.contact = contact;
 22    }
 23
 24    private static String nameWithoutVersion(String name) {
 25        String[] parts = name.split(" ");
 26        if (parts.length > 1 && Character.isDigit(parts[parts.length - 1].charAt(0))) {
 27            StringBuilder output = new StringBuilder();
 28            for (int i = 0; i < parts.length - 1; ++i) {
 29                if (output.length() != 0) {
 30                    output.append(' ');
 31                }
 32                output.append(parts[i]);
 33            }
 34            return output.toString();
 35        } else {
 36            return name;
 37        }
 38    }
 39
 40    public List<Presence> getPresences() {
 41        synchronized (this.presences) {
 42            return new ArrayList<>(this.presences.values());
 43        }
 44    }
 45
 46    public Map<String, Presence> getPresencesMap() {
 47        synchronized (this.presences) {
 48            return new HashMap<>(this.presences);
 49        }
 50    }
 51
 52    public Presence get(String resource) {
 53        synchronized (this.presences) {
 54            return this.presences.get(resource);
 55        }
 56    }
 57
 58    public void updatePresence(String resource, Presence presence) {
 59        synchronized (this.presences) {
 60            this.presences.put(resource, presence);
 61        }
 62    }
 63
 64    public void removePresence(String resource) {
 65        synchronized (this.presences) {
 66            this.presences.remove(resource);
 67        }
 68    }
 69
 70    public void clearPresences() {
 71        synchronized (this.presences) {
 72            this.presences.clear();
 73        }
 74    }
 75
 76    public Presence.Availability getShownStatus() {
 77        Presence.Availability highestAvailability = Presence.Availability.OFFLINE;
 78        synchronized (this.presences) {
 79            for (final Presence p : presences.values()) {
 80                final var availability = p.getAvailability();
 81                if (availability == Presence.Availability.DND) {
 82                    return availability;
 83                } else if (availability.compareTo(highestAvailability) < 0) {
 84                    highestAvailability = availability;
 85                }
 86            }
 87        }
 88        return highestAvailability;
 89    }
 90
 91    public int size() {
 92        synchronized (this.presences) {
 93            return presences.size();
 94        }
 95    }
 96
 97    public boolean isEmpty() {
 98        synchronized (this.presences) {
 99            return this.presences.isEmpty();
100        }
101    }
102
103    public String[] toResourceArray() {
104        synchronized (this.presences) {
105            final String[] presencesArray = new String[presences.size()];
106            presences.keySet().toArray(presencesArray);
107            return presencesArray;
108        }
109    }
110
111    public List<PresenceTemplate> asTemplates() {
112        synchronized (this.presences) {
113            ArrayList<PresenceTemplate> templates = new ArrayList<>(presences.size());
114            for (Presence presence : this.presences.values()) {
115                String message = Strings.nullToEmpty(presence.getStatus()).trim();
116                if (Strings.isNullOrEmpty(message)) {
117                    continue;
118                }
119                templates.add(new PresenceTemplate(presence.getAvailability(), message));
120            }
121            return templates;
122        }
123    }
124
125    public boolean has(String presence) {
126        synchronized (this.presences) {
127            return presences.containsKey(presence);
128        }
129    }
130
131    public Set<String> getStatusMessages() {
132        Set<String> messages = new HashSet<>();
133        synchronized (this.presences) {
134            for (Presence presence : this.presences.values()) {
135                String message = Strings.nullToEmpty(presence.getStatus()).trim();
136                if (Strings.isNullOrEmpty(message)) {
137                    continue;
138                }
139                messages.add(message);
140            }
141        }
142        return messages;
143    }
144
145    public boolean allOrNonSupport(String namespace) {
146        final var connection = this.contact.getAccount().getXmppConnection();
147        if (connection == null) {
148            return true;
149        }
150        synchronized (this.presences) {
151            for (var resource : this.presences.keySet()) {
152                final var disco =
153                        connection
154                                .getManager(DiscoManager.class)
155                                .get(
156                                        Strings.isNullOrEmpty(resource)
157                                                ? contact.getJid().asBareJid()
158                                                : contact.getJid().withResource(resource));
159                if (disco == null || !disco.getFeatureStrings().contains(namespace)) {
160                    return false;
161                }
162            }
163        }
164        return true;
165    }
166
167    public Pair<Map<String, String>, Map<String, String>> toTypeAndNameMap() {
168        Map<String, String> typeMap = new HashMap<>();
169        Map<String, String> nameMap = new HashMap<>();
170        final var connection = this.contact.getAccount().getXmppConnection();
171        if (connection == null) {
172            return new Pair<>(typeMap, nameMap);
173        }
174        synchronized (this.presences) {
175            for (final String resource : this.presences.keySet()) {
176                final var serviceDiscoveryResult =
177                        connection
178                                .getManager(DiscoManager.class)
179                                .get(
180                                        Strings.isNullOrEmpty(resource)
181                                                ? contact.getJid().asBareJid()
182                                                : contact.getJid().withResource(resource));
183                if (serviceDiscoveryResult != null
184                        && !serviceDiscoveryResult.getIdentities().isEmpty()) {
185                    final Identity identity =
186                            Iterables.getFirst(serviceDiscoveryResult.getIdentities(), null);
187                    String type = identity.getType();
188                    String name = identity.getIdentityName();
189                    if (type != null) {
190                        typeMap.put(resource, type);
191                    }
192                    if (name != null) {
193                        nameMap.put(resource, nameWithoutVersion(name));
194                    }
195                }
196            }
197        }
198        return new Pair<>(typeMap, nameMap);
199    }
200}