/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.plugin.generalconfig.autoaway; import java.beans.*; import java.util.*; import net.java.sip.communicator.plugin.generalconfig.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.sysactivity.*; import net.java.sip.communicator.service.sysactivity.event.*; import net.java.sip.communicator.util.*; import org.osgi.framework.*; /** * Listens for idle events from SystemActivityNotifications Service. * * @author Damian Minkov */ public class AutoAwayWatcher implements ServiceListener, RegistrationStateChangeListener { /** * The logger. */ private static final Logger logger = Logger.getLogger(AutoAwayWatcher.class); /** * The states of providers before going to away. */ private final Map<ProtocolProviderService, PresenceStatus> lastStates = new HashMap<ProtocolProviderService, PresenceStatus>(); /** * Listens for idle events. */ private IdleListener idleListener = null; /** * Creates AutoAway handler. */ public AutoAwayWatcher() { if (Preferences.isEnabled()) { start(); } Preferences.addEnableChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if(Boolean.parseBoolean((String) evt.getNewValue())) start(); else stopInner(); } } ); // listens for changes in configured value. Preferences.addTimerChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { stopInner(); start(); } } ); } /** * Starts and add needed listeners. */ private void start() { if(idleListener == null) { idleListener = new IdleListener(); SystemActivityNotificationsService systemActivityNotificationsService = getSystemActivityNotificationsService(); systemActivityNotificationsService.addIdleSystemChangeListener( Preferences.getTimer() * 60 * 1000, idleListener); systemActivityNotificationsService .addSystemActivityChangeListener(idleListener); startListeningForNewProviders(); } } /** * Start listening for new providers and their registration states. */ private void startListeningForNewProviders() { // listen for new providers GeneralConfigPluginActivator.bundleContext.addServiceListener(this); // lets check current providers ServiceReference[] protocolProviderRefs = null; try { protocolProviderRefs = GeneralConfigPluginActivator.bundleContext .getServiceReferences(ProtocolProviderService.class.getName(), null); } catch (InvalidSyntaxException ex) { // this shouldn't happen since we're providing no parameter string // but let's log just in case. logger.error( "Error while retrieving service refs", ex); return; } // in case we found any if (protocolProviderRefs != null) { for (int i = 0; i < protocolProviderRefs.length; i++) { ProtocolProviderService provider = (ProtocolProviderService) GeneralConfigPluginActivator.bundleContext .getService(protocolProviderRefs[i]); this.handleProviderAdded(provider); } } } /** * Stop listening for new providers and their registration states. */ private void stopListeningForNewProviders() { // stop listen for new providers GeneralConfigPluginActivator.bundleContext.removeServiceListener(this); // lets check current providers and remove registration state listener ServiceReference[] protocolProviderRefs = null; try { protocolProviderRefs = GeneralConfigPluginActivator.bundleContext .getServiceReferences(ProtocolProviderService.class.getName(), null); } catch (InvalidSyntaxException ex) { // this shouldn't happen since we're providing no parameter string // but let's log just in case. logger.error( "Error while retrieving service refs", ex); return; } // in case we found any if (protocolProviderRefs != null) { for (int i = 0; i < protocolProviderRefs.length; i++) { ProtocolProviderService provider = (ProtocolProviderService) GeneralConfigPluginActivator.bundleContext .getService(protocolProviderRefs[i]); this.handleProviderRemoved(provider); } } } /** * Stops and removes the listeners. */ public void stop() { GeneralConfigPluginActivator.bundleContext.removeServiceListener(this); stopInner(); } /** * Stops and removes the listeners. */ private void stopInner() { if(idleListener != null) { SystemActivityNotificationsService systemActivityNotificationsService = getSystemActivityNotificationsService(); systemActivityNotificationsService.removeIdleSystemChangeListener( idleListener); systemActivityNotificationsService .removeSystemActivityChangeListener(idleListener); stopListeningForNewProviders(); idleListener = null; } } /** * Change protocol to away saving status so it can be set again when * out of idle state. */ private void changeProtocolsToAway() { for (ProtocolProviderService protocolProvider : GeneralConfigPluginActivator.getProtocolProviders()) { OperationSetPresence presence = protocolProvider.getOperationSet( OperationSetPresence.class); if(presence == null) continue; PresenceStatus status = presence.getPresenceStatus(); if (status.getStatus() < PresenceStatus.AVAILABLE_THRESHOLD) { // already (manually) set to away or lower continue; } PresenceStatus newStatus = StatusUpdateThread.findAwayStatus(presence); try { if (newStatus != null && !status.equals(newStatus)) { addProviderToLastStates(protocolProvider, status); presence.publishPresenceStatus( newStatus, newStatus.getStatusName()); } } catch (IllegalArgumentException e) { } catch (IllegalStateException e) { } catch (OperationFailedException e) { } } } /** * Back to status which was already saved before going to idle. */ private void changeProtocolsToPreviousState() { for (ProtocolProviderService protocolProvider : GeneralConfigPluginActivator.getProtocolProviders()) { PresenceStatus lastState = lastStates.get(protocolProvider); if (lastState != null) { OperationSetPresence presence = protocolProvider.getOperationSet( OperationSetPresence.class); try { presence.publishPresenceStatus(lastState, ""); } catch (IllegalArgumentException e) { } catch (IllegalStateException e) { } catch (OperationFailedException e) { } removeProviderFromLastStates(protocolProvider); } } } /** * The SystemActivityNotifications Service. * @return the SystemActivityNotifications Service. */ private SystemActivityNotificationsService getSystemActivityNotificationsService() { return ServiceUtils.getService( GeneralConfigPluginActivator.bundleContext, SystemActivityNotificationsService.class); } /** * When new protocol provider is registered we add our * registration change listener. * If unregistered remove reference to the provider and the * registration change listener. * * @param serviceEvent ServiceEvent */ public void serviceChanged(ServiceEvent serviceEvent) { Object service = GeneralConfigPluginActivator.bundleContext.getService( serviceEvent.getServiceReference()); // we don't care if the source service is not a protocol provider if (service instanceof ProtocolProviderService) { int serviceEventType = serviceEvent.getType(); if (serviceEventType == ServiceEvent.REGISTERED) handleProviderAdded((ProtocolProviderService) service); else if (serviceEventType == ServiceEvent.UNREGISTERING) handleProviderRemoved((ProtocolProviderService) service); } } /** * Used to set registration state change listener. * * @param provider ProtocolProviderService */ private synchronized void handleProviderAdded( ProtocolProviderService provider) { provider.addRegistrationStateChangeListener(this); } /** * Removes the registration change listener. * * @param provider the ProtocolProviderService that has been unregistered. */ private void handleProviderRemoved(ProtocolProviderService provider) { provider.removeRegistrationStateChangeListener(this); } /** * Remove provider from list with last statuses. * If this is the last provider stop listening for idle events. * @param provider */ private synchronized void removeProviderFromLastStates( ProtocolProviderService provider) { lastStates.remove(provider); } /** * Remember provider's last status, normally before setting it to away. * If needed start listening for idle events. * @param provider the provider. * @param status the status to save. */ private synchronized void addProviderToLastStates( ProtocolProviderService provider, PresenceStatus status) { if(lastStates.size() == 0) start(); lastStates.put(provider, status); } /** * Listens for provider states. * @param evt */ public void registrationStateChanged(RegistrationStateChangeEvent evt) { if(evt.getSource() instanceof ProtocolProviderService) { if(evt.getNewState().equals(RegistrationState.UNREGISTERED) || evt.getNewState().equals(RegistrationState.CONNECTION_FAILED)) { removeProviderFromLastStates(evt.getProvider()); } else if(evt.getNewState().equals( RegistrationState.REGISTERED)) { // we have at least one provider, so lets start listening if(lastStates.size() == 0) { start(); } else { // or check are we away if(getSystemActivityNotificationsService() .getTimeSinceLastInput() > Preferences.getTimer()*60*1000) { // we are away, so update the newly registered provider // do it in new thread to give the provider // time dispatch his status new Thread(new Runnable() { public void run() { try{ Thread.sleep(1000); } catch(Throwable t){} changeProtocolsToAway(); } }).start(); } } } } } /** * Listener waiting for idle state change. */ private class IdleListener implements SystemActivityChangeListener { /** * Listens for activities and set corresponding statuses. * * @param event the <tt>NotificationActionTypeEvent</tt>, which is */ public void activityChanged(SystemActivityEvent event) { switch(event.getEventID()) { case SystemActivityEvent.EVENT_DISPLAY_SLEEP: case SystemActivityEvent.EVENT_SCREEN_LOCKED: case SystemActivityEvent.EVENT_SCREENSAVER_START: case SystemActivityEvent.EVENT_SYSTEM_IDLE: changeProtocolsToAway(); break; case SystemActivityEvent.EVENT_DISPLAY_WAKE: case SystemActivityEvent.EVENT_SCREEN_UNLOCKED: case SystemActivityEvent.EVENT_SCREENSAVER_STOP: case SystemActivityEvent.EVENT_SYSTEM_IDLE_END: changeProtocolsToPreviousState(); break; } } } }