diff options
author | Damian Minkov <damencho@jitsi.org> | 2013-10-03 11:31:24 +0300 |
---|---|---|
committer | Damian Minkov <damencho@jitsi.org> | 2013-10-03 11:32:24 +0300 |
commit | c33c7cdfcf8199acb6e14766b13ad2fe9df7c777 (patch) | |
tree | 3d79b52836484cc3e3f2029efdebe5585c3738be /src/net/java/sip | |
parent | b0c9b7e4c700c19b18c41a56022b8000603f4c19 (diff) | |
download | jitsi-c33c7cdfcf8199acb6e14766b13ad2fe9df7c777.zip jitsi-c33c7cdfcf8199acb6e14766b13ad2fe9df7c777.tar.gz jitsi-c33c7cdfcf8199acb6e14766b13ad2fe9df7c777.tar.bz2 |
Adds mobile indicator icon next contacts when there are detected to be logged in only from a mobile device.
Diffstat (limited to 'src/net/java/sip')
8 files changed, 391 insertions, 1 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java index 35baa43..6feec83 100755 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java @@ -1211,7 +1211,8 @@ public class ChatWritePanel if (transportSelectorBox != null) transportSelectorBox.removeChatTransport(chatTransport); - if(transportSelectorBox.getMenu().getItemCount() == 1 + if(transportSelectorBox != null + && transportSelectorBox.getMenu().getItemCount() == 1 && ConfigurationUtils.isHideAccountSelectionWhenPossibleEnabled()) { transportSelectorBox.setVisible(false); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java index 25e1f86..60225a4 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java @@ -403,6 +403,9 @@ public class ContactListTreeCellRenderer } } + // clear icon if any (mobile indicator) + this.nameLabel.setIcon(null); + // Make appropriate adjustments for contact nodes and group nodes. if (value instanceof ContactNode) { @@ -439,6 +442,15 @@ public class ContactListTreeCellRenderer // contains a status message. this.initDisplayDetails(contact.getDisplayDetails()); + // Checks and set mobile indicator + if (contact.getDescriptor() instanceof MetaContact + && isMobile((MetaContact)contact.getDescriptor())) + { + this.nameLabel.setIcon(new ImageIcon(ImageLoader.getImage( + ImageLoader.CONTACT_LIST_MOBILE_INDICATOR))); + this.nameLabel.setHorizontalTextPosition(SwingConstants.LEFT); + } + if (this.treeContactList.isContactButtonsVisible()) this.initButtonsPanel(contact); @@ -528,6 +540,26 @@ public class ContactListTreeCellRenderer } /** + * Checks whether metaContact has mobile indicator. + * Needs all of the contacts to have it to indicate it. + * @param metaContact the metacontact to check for mobile indicator + * @return whether to indicate contact as mobile one. + */ + private boolean isMobile(MetaContact metaContact) + { + Iterator<Contact> iter = metaContact.getContacts(); + while(iter.hasNext()) + { + Contact contact = iter.next(); + + if(!contact.isMobile()) + return false; + } + + return metaContact.getContactCount() > 0 ? true : false; + } + + /** * Paints a customized background. * * @param g the <tt>Graphics</tt> object through which we paint diff --git a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java index 7802329..77c6772 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java +++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java @@ -248,6 +248,12 @@ public class ImageLoader = new ImageID("service.gui.buttons.CONTACT_LIST_BUTTON_SEPARATOR"); /** + * The mobile indicator for contacts in contact list. + */ + public static final ImageID CONTACT_LIST_MOBILE_INDICATOR + = new ImageID("service.gui.buttons.CONTACT_LIST_MOBILE_INDICATOR"); + + /** * The call button small image. */ public static final ImageID CALL_BUTTON_SMALL diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java index 644059a..d0e0f00 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java @@ -80,6 +80,11 @@ public class ContactJabberImpl private Map<String, ContactResourceJabberImpl> resources = null; /** + * Whether this contact is a mobile one. + */ + private boolean mobile = false; + + /** * Creates an JabberContactImpl * @param rosterEntry the RosterEntry object that we will be encapsulating. * @param ssclCallback a reference to the ServerStoredContactListImpl @@ -622,4 +627,25 @@ public class ContactJabberImpl = new ConcurrentHashMap<String, ContactResourceJabberImpl>(); } } + + /** + * Whether contact is mobile one. Logged in from mobile device. + * @return whether contact is mobile one. + */ + public boolean isMobile() + { + if(!getPresenceStatus().isOnline()) + return false; + + return mobile; + } + + /** + * Changes the mobile indicator value. + * @param mobile is mobile + */ + void setMobile(boolean mobile) + { + this.mobile = mobile; + } }
\ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java b/src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java new file mode 100644 index 0000000..28caec9 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/MobileIndicator.java @@ -0,0 +1,304 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.caps.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import org.jivesoftware.smack.util.*; + +import java.util.*; + +/** + * Handles all the logic about mobile indicator for contacts. + * Has to modes, the first is searching for particular string in the beginning + * of the contact resource and if found and this is the highest priority then + * the contact in on mobile. + * The second one and the default one is searching for strings in the node + * from the contact caps and if found and this is the most connected device + * then the contact is a mobile one. + * + * @author Damian Minkov + */ +public class MobileIndicator + implements RegistrationStateChangeListener, + UserCapsNodeListener +{ + /** + * The parent provider. + */ + private final ProtocolProviderServiceJabberImpl parentProvider; + + /** + * Whether we are using the default method for checking for + * mobile indicator. + */ + private boolean isCapsMobileIndicator = true; + + /** + * The strings that we will check. + */ + private final String[] checkStrings; + + /** + * A reference to the ServerStoredContactListImpl instance. + */ + private final ServerStoredContactListJabberImpl ssclCallback; + + /** + * The account property to activate the mode for checking the resource + * names, the strings to check whether a resource starts with can be + * entered separated by comas. + */ + private static final String MOBILE_INDICATOR_RESOURCE_ACC_PROP = + "MOBILE_INDICATOR_RESOURCE"; + + /** + * The account property to activate the mode for checking the contact + * caps, the strings to check whether a caps contains with can be + * entered separated by comas. + */ + private static final String MOBILE_INDICATOR_CAPS_ACC_PROP = + "MOBILE_INDICATOR_CAPS"; + + /** + * Construct Mobile indicator. + * @param parentProvider the parent provider. + * @param ssclCallback the callback for the contact list to obtain contacts. + */ + public MobileIndicator(ProtocolProviderServiceJabberImpl parentProvider, + ServerStoredContactListJabberImpl ssclCallback) + { + this.parentProvider = parentProvider; + this.ssclCallback = ssclCallback; + + String indicatorResource = parentProvider.getAccountID() + .getAccountProperties().get(MOBILE_INDICATOR_RESOURCE_ACC_PROP); + if(indicatorResource != null + && indicatorResource.length() > 0) + { + isCapsMobileIndicator = false; + checkStrings = indicatorResource.split(","); + } + else + { + String indicatorCaps = parentProvider.getAccountID() + .getAccountProperties().get(MOBILE_INDICATOR_CAPS_ACC_PROP); + if(indicatorCaps == null + || indicatorCaps.length() == 0) + { + indicatorCaps = "android"; + } + + checkStrings = indicatorCaps.split(","); + + this.parentProvider.addRegistrationStateChangeListener(this); + } + } + + /** + * Called when resources have been updated for a contact, on + * presence changed. + * @param contact the contact + */ + public void resourcesUpdated(ContactJabberImpl contact) + { + if(isCapsMobileIndicator) + { + // we update it also here, cause sometimes caps update comes + // before presence changed and contacts are still offline + // and we dispatch wrong initial mobile indicator + updateMobileIndicatorUsingCaps(contact.getAddress()); + return; + } + + // checks resource starts with String and is current highest priority + int highestPriority = Integer.MIN_VALUE; + List<ContactResource> highestPriorityResources = + new ArrayList<ContactResource>(); + + for(ContactResource res : contact.getResources()) + { + if(!res.getPresenceStatus().isOnline()) + continue; + + int prio = res.getPriority(); + + if(prio >= highestPriority) + { + if(highestPriority != prio) + highestPriorityResources.clear(); + + highestPriority = prio; + + highestPriorityResources.add(res); + } + } + + // check whether all are mobile + boolean allMobile = false; + for(ContactResource res : highestPriorityResources) + { + if(startsWithStrings(res.getResourceName(), checkStrings)) + allMobile = true; + else + { + allMobile = false; + break; + } + } + + if(highestPriorityResources.size() > 0) + contact.setMobile(allMobile); + else + contact.setMobile(false); + } + + /** + * The method is called by a ProtocolProvider implementation whenever + * a change in the registration state of the corresponding provider had + * occurred. + * @param evt ProviderStatusChangeEvent the event describing the status + * change. + */ + public void registrationStateChanged(RegistrationStateChangeEvent evt) + { + if(evt.getNewState() == RegistrationState.REGISTERED) + { + this.parentProvider.getDiscoveryManager() + .getCapsManager().addUserCapsNodeListener(this); + } + } + + /** + * Caps for user has been changed. + * @param user the user (full JID) + * @param node the entity caps node#ver + * @param online indicates if the user for which we're notified is online + */ + @Override + public void userCapsNodeAdded(String user, String node, boolean online) + { + updateMobileIndicatorUsingCaps(user); + } + + /** + * Caps for user has been changed. + * @param user the user (full JID) + * @param node the entity caps node#ver + * @param online indicates if the user for which we're notified is online + */ + @Override + public void userCapsNodeRemoved(String user, String node, boolean online) + { + updateMobileIndicatorUsingCaps(user); + } + + /** + * Update mobile indicator for contact, searching in contact caps. + * @param user the contact address with or without resource. + */ + private void updateMobileIndicatorUsingCaps(String user) + { + ContactJabberImpl contact = + ssclCallback.findContactById(StringUtils.parseBareAddress(user)); + + if(contact == null) + return; + + // Now lets check for mobile indicator + EntityCapsManager capsManager = ssclCallback.getParentProvider() + .getDiscoveryManager().getCapsManager(); + + // 1. Find most connected resources and if all are mobile + int currentMostConnectedStatus = 0; + List<ContactResource> mostAvailableResources = + new ArrayList<ContactResource>(); + + for(ContactResource res : contact.getResources()) + { + if(!res.getPresenceStatus().isOnline()) + continue; + + int status = res.getPresenceStatus().getStatus(); + + if(status > currentMostConnectedStatus) + { + if(currentMostConnectedStatus != status) + mostAvailableResources.clear(); + + currentMostConnectedStatus = status; + + mostAvailableResources.add(res); + } + } + + // check whether all are mobile + boolean allMobile = false; + for(ContactResource res : mostAvailableResources) + { + EntityCapsManager.Caps caps = capsManager.getCapsByUser( + ((ContactResourceJabberImpl)res).getFullJid()); + + if(caps == null) + { + // missing caps, no indicator so its not mobile + allMobile = false; + break; + } + + if(containsStrings(caps.node, checkStrings)) + allMobile = true; + else + { + allMobile = false; + break; + } + } + + if(mostAvailableResources.size() > 0) + contact.setMobile(allMobile); + else + contact.setMobile(false); + } + + /** + * Checks whether <tt>value</tt> starts + * one of the <tt>checkStrs</> Strings. + * @param value the value to check + * @param checkStrs an array of strings we are searching for. + * @return <tt>true</tt> if <tt>value</tt> starts one of the Strings. + */ + private static boolean startsWithStrings(String value, String[] checkStrs) + { + for(String str : checkStrs) + { + if(str.length() > 0 && value.startsWith(str)) + return true; + } + + return false; + } + + /** + * Checks whether <tt>value</tt> contains + * one of the <tt>checkStrs</> Strings. + * @param value the value to check + * @param checkStrs an array of strings we are searching for. + * @return <tt>true</tt> if <tt>value</tt> contains one of the Strings. + */ + private static boolean containsStrings(String value, String[] checkStrs) + { + for(String str : checkStrs) + { + if(str.length() > 0 && value.contains(str)) + return true; + } + + return false; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java index ca90432..d3796ad 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java @@ -109,6 +109,8 @@ public class OperationSetPersistentPresenceJabberImpl private VCardTempXUpdatePresenceExtension vCardTempXUpdatePresenceExtension = null; + private final MobileIndicator mobileIndicator; + /** * Creates the OperationSet. * @param provider the parent provider. @@ -131,6 +133,8 @@ public class OperationSetPersistentPresenceJabberImpl parentProvider.addRegistrationStateChangeListener( new RegistrationStateListener()); + + mobileIndicator = new MobileIndicator(parentProvider, ssContactList); } /** @@ -1157,6 +1161,7 @@ public class OperationSetPersistentPresenceJabberImpl // When status changes this may be related to a change in the // available resources. sourceContact.updateResources(); + mobileIndicator.resourcesUpdated(sourceContact); PresenceStatus oldStatus = sourceContact.getPresenceStatus(); diff --git a/src/net/java/sip/communicator/service/protocol/AbstractContact.java b/src/net/java/sip/communicator/service/protocol/AbstractContact.java index 1a87ecd..5b4052a 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractContact.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractContact.java @@ -179,4 +179,13 @@ public abstract class AbstractContact { return getAddress(); } + + /** + * Whether contact is mobile one. Logged in only from mobile device. + * @return whether contact is mobile one. + */ + public boolean isMobile() + { + return false; + } } diff --git a/src/net/java/sip/communicator/service/protocol/Contact.java b/src/net/java/sip/communicator/service/protocol/Contact.java index 96915cd..335e206 100644 --- a/src/net/java/sip/communicator/service/protocol/Contact.java +++ b/src/net/java/sip/communicator/service/protocol/Contact.java @@ -158,4 +158,11 @@ public interface Contact * @return the address of the contact. */ public String getPersistableAddress(); + + /** + * Whether contact is mobile one. Logged in only from mobile device. + * @return whether contact is mobile one. + */ + public boolean isMobile(); + } |