Skip to content

Commit

Permalink
[im] Add RosterListener.ownPresenceChanged(Presence)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Flowdalic committed Oct 5, 2024
1 parent e376f55 commit b88a363
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 23 deletions.
60 changes: 37 additions & 23 deletions smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java
Original file line number Diff line number Diff line change
Expand Up @@ -1432,12 +1432,22 @@ private void fireRosterChangedEvent(final Collection<Jid> 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);
}
}
}
}
Expand Down Expand Up @@ -1633,28 +1643,31 @@ 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.
Expand All @@ -1668,8 +1681,10 @@ 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() {
@Override
public void run() {
Expand Down Expand Up @@ -1701,10 +1716,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);
}
Expand All @@ -1724,10 +1739,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
Expand Down Expand Up @@ -1761,10 +1775,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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) { };
}

0 comments on commit b88a363

Please sign in to comment.