/** * $RCSfile: ,v $ * $Revision: $ * $Date: $ * * Copyright (C) 2004-2011 Jive Software. All rights reserved. * * 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 org.jivesoftware.sparkplugin.ui.call; import net.java.sipmack.sip.Call; import net.java.sipmack.sip.InterlocutorUI; import net.java.sipmack.sip.event.CallListener; import net.java.sipmack.sip.event.CallStateEvent; import net.java.sipmack.softphone.SoftPhoneManager; import net.java.sipmack.softphone.listeners.InterlocutorListener; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smackx.packet.VCard; import org.jivesoftware.spark.ChatManager; import org.jivesoftware.spark.SparkManager; import org.jivesoftware.spark.component.tabbedPane.SparkTab; import org.jivesoftware.spark.component.tabbedPane.SparkTabbedPaneListener; import org.jivesoftware.spark.phone.PhoneManager; import org.jivesoftware.spark.ui.ChatContainer; import org.jivesoftware.spark.ui.ChatRoom; import org.jivesoftware.spark.util.SwingWorker; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.plugin.alerts.SparkToaster; import javax.swing.JOptionPane; import java.awt.Component; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; import org.jivesoftware.spark.plugin.phone.resource.PhoneRes; /** * */ public class CallManager implements InterlocutorListener { private static CallManager singleton; private static final Object LOCK = new Object(); private SoftPhoneManager softPhone; private final Map<String, PhonePanel> calls = new HashMap<String, PhonePanel>(); private Presence offPhonePresence; private Map<InterlocutorUI, SparkToaster> toasters = new HashMap<InterlocutorUI, SparkToaster>(); /** * Returns the singleton instance of <CODE>CallManager</CODE>, * creating it if necessary. * <p/> * * @return the singleton instance of <Code>CallManager</CODE> */ public static CallManager getInstance() { // Synchronize on LOCK to ensure that we don't end up creating // two singletons. synchronized (LOCK) { if (null == singleton) { CallManager controller = new CallManager(); singleton = controller; return controller; } } return singleton; } private CallManager() { softPhone = SoftPhoneManager.getInstance(); softPhone.addInterlocutorListener(this); SparkManager.getChatManager().getChatContainer().addSparkTabbedPaneListener(new SparkTabbedPaneListener() { public void tabRemoved(SparkTab tab, Component component, int index) { removePhonePanel(component); } public void tabAdded(SparkTab tab, Component component, int index) { } public void tabSelected(SparkTab tab, Component component, int index) { } public void allTabsRemoved() { } public boolean canTabClose(SparkTab tab, Component component) { PhonePanel phonePanel = null; if (component instanceof PhonePanel) { phonePanel = (PhonePanel) component; } if (phonePanel == null && component instanceof ChatRoom) { final ChatRoom chatRoom = (ChatRoom) component; Component rightComponent = chatRoom.getSplitPane().getRightComponent(); if (rightComponent instanceof PhonePanel) { phonePanel = (PhonePanel) rightComponent; } } if (phonePanel == null) { return true; } if (component instanceof PhonePanel) { final InterlocutorUI ic = phonePanel.getActiveCall(); if (ic.getCallState().equals(Call.CONNECTED)) { // Prompt to close this window int ok = JOptionPane.showConfirmDialog(component, PhoneRes.getIString("phone.closeconfirm"), PhoneRes.getIString("phone.confirmation"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); boolean close = (ok == JOptionPane.YES_OPTION); if (close) { // End Call softPhone.getDefaultGuiManager().hangup(ic); return true; } else { return false; } } } return true; } }); } public void busy() { } private void showIncomingCall(final InterlocutorUI ic) { try { EventQueue.invokeAndWait(new Runnable(){ public void run() { final SparkToaster toasterManager = new SparkToaster(); toasters.put(ic, toasterManager); final IncomingCallUI incomingCall = new IncomingCallUI(ic); toasterManager.setToasterHeight(230); toasterManager.setToasterWidth(300); toasterManager.setDisplayTime(500000000); toasterManager.showToaster(PhoneRes.getIString("phone.incomingcall"), incomingCall); toasterManager.hideTitle(); toasterManager.setHidable(false); incomingCall.getAcceptButton().addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SparkManager.getMainWindow().toFront(); closeToaster(ic); SoftPhoneManager.getInstance().getDefaultGuiManager().answer(); } }); incomingCall.getRejectButton().addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { closeToaster(ic); SoftPhoneManager.getInstance().getDefaultGuiManager().hangup(ic); } }); } }); } catch(Exception e) { Log.error(e); } } private void showOutgoingCall(final InterlocutorUI ic) { final SparkToaster toasterManager = new SparkToaster(); toasters.put(ic, toasterManager); final OutgoingCallUI incomingCall = new OutgoingCallUI(ic); toasterManager.setToasterHeight(230); toasterManager.setToasterWidth(300); toasterManager.setDisplayTime(500000000); toasterManager.setHidable(false); toasterManager.showToaster(PhoneRes.getIString("phone.incomingcall"), incomingCall); toasterManager.hideTitle(); incomingCall.getRejectButton().addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { closeToaster(ic); SoftPhoneManager.getInstance().getDefaultGuiManager().hangup(ic); } }); } public void interlocutorAdded(final InterlocutorUI interlocutorUI) { Presence current = SparkManager.getWorkspace().getStatusBar().getPresence(); // Set offline presence if necessary. if (offPhonePresence == null || !(current.getType().equals(Presence.Type.available) && current.getStatus().equals("On Phone") && current.getMode().equals(Presence.Mode.away))) { offPhonePresence = current; } // Send on phone presence Presence onPhonePresence = new Presence(Presence.Type.available, "On Phone", -1, Presence.Mode.away); SparkManager.getSessionManager().changePresence(onPhonePresence); interlocutorUI.getCall().addStateChangeListener(new CallListener() { public void callStateChanged(CallStateEvent evt) { final String callState = evt.getNewState(); String callNumber = interlocutorUI.getCall().getNumber(); callNumber = SoftPhoneManager.getNumbersFromPhone(callNumber); PhonePanel panel = calls.get(callNumber); if (callState.equals(Call.CONNECTED)) { closeToaster(interlocutorUI); showCallAnswered(interlocutorUI); } else if (callState.equals(Call.DISCONNECTED)) { closeToaster(interlocutorUI); if (panel != null) { panel.callEnded(); } PhoneManager.getInstance().removeCurrentCall(callNumber); } else if (callState.equals(Call.RINGING)) { } else if (callState.equals(Call.BUSY)) { closeToaster(interlocutorUI); } else if (callState.equals(Call.ALERTING)) { showIncomingCall(interlocutorUI); PhoneManager.getInstance().addCurrentCall(callNumber); } } }); final String callState = interlocutorUI.getCallState(); if (callState != null && (callState.equals(Call.DIALING)) || callState.equals(Call.RINGING)) { showOutgoingCall(interlocutorUI); } } private void showCallAnswered(final InterlocutorUI interlocutorUI) { final ChatManager chatManager = SparkManager.getChatManager(); try { EventQueue.invokeAndWait(new Runnable(){ public void run() { String phoneNumber = interlocutorUI.getCall().getNumber(); phoneNumber = SoftPhoneManager.getNumbersFromPhone(phoneNumber); PhonePanel panel = calls.get(phoneNumber); ChatRoom chatRoom = null; if (panel == null) { // Let's check to see if the Contact Exists final VCard vcard = SparkManager.getVCardManager().searchPhoneNumber(phoneNumber); if (vcard != null) { panel = new RosterMemberPanel(); panel.setInterlocutorUI(interlocutorUI); String jid = vcard.getJabberId(); String nickname = SparkManager.getUserManager().getUserNicknameFromJID(jid); chatRoom = chatManager.createChatRoom(jid, nickname, nickname); chatRoom.getSplitPane().setRightComponent(panel); chatRoom.getSplitPane().setResizeWeight(.80); chatRoom.getSplitPane().setDividerSize(5); chatManager.getChatContainer().activateChatRoom(chatRoom); } else { panel = new NonRosterPanel(); panel.setInterlocutorUI(interlocutorUI); chatManager.getChatContainer().addContainerComponent(panel); chatManager.getChatContainer().activateComponent(panel); } calls.put(phoneNumber, panel); } else { panel.setInterlocutorUI(interlocutorUI); } if (chatRoom != null) { SoftPhoneManager.getInstance().addCallSession(chatRoom, SoftPhoneManager.CallRoomState.inCall); SparkManager.getChatManager().notifySparkTabHandlers(chatRoom); } else { SoftPhoneManager.getInstance().addCallSession(panel, SoftPhoneManager.CallRoomState.inCall); SparkManager.getChatManager().notifySparkTabHandlers(panel); } } }); } catch(Exception e){ Log.error(e); } } public void interlocutorRemoved(final InterlocutorUI interlocutorUI) { if (softPhone.getInterlocutors().size() == 0) { if (offPhonePresence == null) { // Set user to available when all phone calls are hung up. Presence availablePresence = new Presence(Presence.Type.available, "Available", 1, Presence.Mode.available); SparkManager.getSessionManager().changePresence(availablePresence); } else { // Set user presence to last one choosed SparkManager.getSessionManager().changePresence(offPhonePresence); } offPhonePresence = null; } final SwingWorker delay = new SwingWorker() { public Object construct() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return true; } public void finished() { String phoneNumber = interlocutorUI.getCall().getNumber(); phoneNumber = SoftPhoneManager.getNumbersFromPhone(phoneNumber); final PhonePanel phonePanel = calls.get(phoneNumber); if (phonePanel == null) { return; } for (ChatRoom room : SparkManager.getChatManager().getChatContainer().getChatRooms()) { Component comp = room.getSplitPane().getRightComponent(); if (comp != null && comp instanceof PhonePanel) { final PhonePanel cp = (PhonePanel) comp; if (cp == phonePanel) { room.getSplitPane().setRightComponent(null); removePhonePanel(cp); // Remove state mapping softPhone.removeCallSession(room); SparkManager.getChatManager().notifySparkTabHandlers(room); } return; } } } }; delay.start(); } /** * Removes PhonePanel from ChatContainer or associated ChatRoom. * * @param component the PhonePanel or ChatRoom containing the PhonePanel. */ private void removePhonePanel(Component component) { String phoneNumber = null; if (component instanceof PhonePanel) { final PhonePanel phonePanel = (PhonePanel) component; phoneNumber = phonePanel.getPhoneNumber(); phoneNumber = SoftPhoneManager.getNumbersFromPhone(phoneNumber); } else if (component instanceof ChatRoom) { ChatRoom chatRoom = (ChatRoom) component; Component comp = chatRoom.getSplitPane().getRightComponent(); if (comp != null && comp instanceof PhonePanel) { final PhonePanel phonePanel = (PhonePanel) comp; phoneNumber = phonePanel.getPhoneNumber(); phoneNumber = SoftPhoneManager.getNumbersFromPhone(phoneNumber); } } if (phoneNumber != null) { calls.remove(phoneNumber); } } /** * Retrieves the <code>PhonePanel</code> object from the <code>ChatRoom</code>. * If no PhonePanel exists, then null is returned. * * @param chatRoom the ChatRoom. * @return the PhonePanel. */ public PhonePanel getPhonePanel(ChatRoom chatRoom) { Component comp = chatRoom.getSplitPane().getRightComponent(); if (comp != null && comp instanceof PhonePanel) { final PhonePanel phonePanel = (PhonePanel) comp; return phonePanel; } return null; } /** * Returns the associated Chat Room if one exists. * * @param phonePanel the <code>PhonePanel</code>. * @return the ChatRoom. */ public ChatRoom getAssociatedChatRoom(PhonePanel phonePanel) { for (ChatRoom chatRoom : SparkManager.getChatManager().getChatContainer().getChatRooms()) { Component comp = chatRoom.getSplitPane().getRightComponent(); if (phonePanel.equals(comp)) { return chatRoom; } } return null; } /** * Returns the <code>SparkTab</code> that acts as a container to this PhonePanel. * * @param phonePanel the <code>PhonePanel</code> * @return the SparkTab. */ public SparkTab getSparkTab(PhonePanel phonePanel) { final ChatContainer chatContainer = SparkManager.getChatManager().getChatContainer(); int tabCount = chatContainer.getTabCount(); for (int i = 0; i < tabCount; i++) { SparkTab sparkTab = chatContainer.getTabAt(i); Component containerComponent = chatContainer.getComponentInTab(sparkTab); if (containerComponent.equals(phonePanel)) { return sparkTab; } if (containerComponent instanceof ChatRoom) { ChatRoom chatRoom = (ChatRoom) containerComponent; Component rightComponent = chatRoom.getSplitPane().getRightComponent(); if (phonePanel.equals(rightComponent)) { return sparkTab; } } } return null; } private void closeToaster(InterlocutorUI ic) { SparkToaster toaster = toasters.get(ic); if (toaster != null) { toaster.close(); toasters.remove(ic); } } }