From e460da86c405e6f80ea62da6af87a4549e542438 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 5 Oct 2024 14:19:49 +0200 Subject: [PATCH] [im] Add RosterListener.ownPresenceChanged(Presence) Reflected own-presences where not processed by the RosterListener. However, most UIs probably want to display also the own presence, especially the presence status of other available resources of the own account. The new ownPresenceChanged() method allows to listen for those presences. --- .../org/jivesoftware/smack/roster/Roster.java | 58 +++++++++++-------- .../smack/roster/RosterListener.java | 9 +++ 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index b515420158..6593cf0d24 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -1432,12 +1432,22 @@ private void fireRosterChangedEvent(final Collection addedEntries, final Co /** * Fires roster presence changed event to roster listeners. * + * @param bareFrom the bare JID that send the presence. + * @param ownPresence true if this is a presence from one of our available resources. * @param presence the presence change. */ - private void fireRosterPresenceEvent(final Presence presence) { + private void fireRosterPresenceEvent(BareJid bareFrom, boolean ownPresence, Presence presence) { + if (!ownPresence && !contains(bareFrom)) { + return; + } + synchronized (rosterListenersAndEntriesLock) { for (RosterListener listener : rosterListeners) { - listener.presenceChanged(presence); + if (ownPresence) { + listener.ownPresenceChanged(presence); + } else { + listener.presenceChanged(presence); + } } } } @@ -1633,28 +1643,30 @@ public void processStanza(Stanza packet) throws NotConnectedException, Interrupt } final Jid from = packet.getFrom(); + final Presence presence = (Presence) packet; + final XMPPConnection connection = connection(); + if (connection == null) { + LOGGER.finest("Connection was null while trying to handle exotic presence stanza: " + presence); + return; + } if (!isLoaded() && rosterLoadedAtLogin) { - XMPPConnection connection = connection(); - // Only log the warning, if this is not the reflected self-presence. Otherwise, // the reflected self-presence may cause a spurious warning in case the // connection got quickly shut down. See SMACK-941. - if (connection != null && from != null && !from.equals(connection.getUser())) { + if (from != null && !from.equals(connection.getUser())) { LOGGER.warning("Roster not loaded while processing " + packet); } } - final Presence presence = (Presence) packet; final BareJid key; + final boolean ownPresence; if (from != null) { + EntityFullJid myJid = connection.getUser(); + ownPresence = from.isParentOf(myJid); + key = from.asBareJid(); } else { - XMPPConnection connection = connection(); - if (connection == null) { - LOGGER.finest("Connection was null while trying to handle exotic presence stanza: " + presence); - return; - } // Assume the presence come "from the users account on the server" since no from was set (RFC 6120 ยง // 8.1.2.1 4.). Note that getUser() may return null, but should never return null in this case as where // connected. @@ -1668,6 +1680,7 @@ public void processStanza(Stanza packet) throws NotConnectedException, Interrupt } LOGGER.info("Exotic presence stanza without from received: " + presence); key = myJid.asBareJid(); + ownPresence = true; } asyncButOrdered.performAsyncButOrdered(key, new Runnable() { @@ -1701,10 +1714,10 @@ public void run() { userPresences.remove(Resourcepart.EMPTY); // Add the new presence, using the resources as a key. userPresences.put(fromResource, presence); - // If the user is in the roster, fire an event. - if (contains(key)) { - fireRosterPresenceEvent(presence); - } + + // If the user is in the roster or if its our own presence, fire an event. + fireRosterPresenceEvent(key, ownPresence, presence); + for (PresenceEventListener presenceEventListener : presenceEventListeners) { presenceEventListener.presenceAvailable(fullFrom, presence); } @@ -1724,10 +1737,9 @@ public void run() { // such as the user being on vacation. userPresences.put(fromResource, presence); } - // If the user is in the roster, fire an event. - if (contains(key)) { - fireRosterPresenceEvent(presence); - } + + // If the user is in the roster or if its our own presence, fire an event. + fireRosterPresenceEvent(key, ownPresence, presence); // Ensure that 'from' is a full JID before invoking the presence unavailable // listeners. Usually unavailable presences always have a resourcepart, i.e. are @@ -1761,10 +1773,10 @@ public void run() { // Set the new presence using the empty resource as a key. userPresences.put(Resourcepart.EMPTY, presence); - // If the user is in the roster, fire an event. - if (contains(key)) { - fireRosterPresenceEvent(presence); - } + + // If the user is in the roster or if its our own presence, fire an event. + fireRosterPresenceEvent(key, ownPresence, presence); + for (PresenceEventListener presenceEventListener : presenceEventListeners) { presenceEventListener.presenceError(from, presence); } diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterListener.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterListener.java index 005b703e94..a8d2e2e636 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterListener.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterListener.java @@ -79,4 +79,13 @@ public interface RosterListener { * @see Roster#getPresence(org.jxmpp.jid.BareJid) */ void presenceChanged(Presence presence); + + /** + * Called when the presence of one of the own available resources is changed. + * + * @param presence the presence that changed. + * @see Roster#getPresence(org.jxmpp.jid.BareJid) + * @since 4.5 + */ + default void ownPresenceChanged(Presence presence) { }; }