Adds UI for cross protocol conference calls. Adds also the possibility to add an incoming call into an existing call/conference. Fixes also the drag'n'drop for cross-protocol accounts.

cusax-fix
Sebastien Vincent 14 years ago
parent 0f119431f4
commit 2ffab015c4

@ -125,6 +125,7 @@ service.gui.statusicons.USER_ON_THE_PHONE_ICON=resources/images/impl/gui/common/
# service gui buttons
service.gui.buttons.CALL_BUTTON_BG=resources/images/impl/gui/buttons/callButton.png
service.gui.buttons.MERGE_CALL_BUTTON_BG=resources/images/impl/gui/buttons/mergeToCall.png
service.gui.buttons.CALL_VIDEO_BUTTON_BG=resources/images/impl/gui/buttons/videoCallButton.png
service.gui.buttons.CALL_BUTTON_SMALL=resources/images/impl/gui/buttons/callSmall.png
service.gui.buttons.CALL_BUTTON_SMALL_PRESSED=resources/images/impl/gui/buttons/callSmallPressed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -85,7 +85,8 @@ public void run()
Call sourceCall = event.getSourceCall();
final ReceivedCallDialog receivedCallDialog
= new ReceivedCallDialog(sourceCall, event.isVideoCall());
= new ReceivedCallDialog(sourceCall, event.isVideoCall(),
(CallManager.getActiveCalls().size() > 0));
receivedCallDialog.setVisible(true);
@ -110,7 +111,8 @@ public void callStateChanged(CallChangeEvent evt)
.equals(CallState.CALL_INITIALIZATION)
|| evt.getNewValue()
.equals(CallState.CALL_IN_PROGRESS))
&& activeCalls.get(call) == null)
&& activeCalls.get(call) == null &&
call.getCallGroup() == null)
{
openCallContainer(call);
}
@ -193,6 +195,33 @@ public static void answerCall(final Call call)
new AnswerCallThread(call).start();
}
/**
* Answers the given call in an existing call. It will end up with a
* conference call.
*
* @param call the call to answer
*/
public static void answerCallInFirstExistingCall(final Call call)
{
Call existingCall = null;
// pick up the first available call
for(Call c : activeCalls.keySet())
{
existingCall = c;
break;
}
if(existingCall == null)
{
answerCall(call);
}
else
{
new AnswerCallThread(call, existingCall).start();
}
}
/**
* Answers the given call with video.
*
@ -681,17 +710,11 @@ public static void createCall( String callString,
// Removes special characters from phone numbers.
if (ConfigurationManager.isNormalizePhoneNumber())
{
if (!StringUtils.containsLetters(callString)
&& GuiActivator.getPhoneNumberService()
.isPhoneNumber(callString))
{
callString = GuiActivator.getPhoneNumberService()
.normalize(callString);
}
else
{
callString = StringUtils.concatenateWords(callString);
}
String normalizedContact[] = new String[1];
normalizedContact[0] = callString;
normalizePhoneNumbers(normalizedContact);
callString = normalizedContact[0];
}
List<ProtocolProviderService> telephonyProviders
@ -759,19 +782,28 @@ public static void inviteToConferenceCall( String[] callees,
* Invites the given list of <tt>callees</tt> to the given conference
* <tt>call</tt>.
*
* @param provider provider to which the callee belongs
* @param callee the list of contacts to invite
* @param callees the list of contacts to invite
* @param call existing call
*/
public static void inviteToCrossProtocolConferenceCall(
ProtocolProviderService provider,
String callee,
Map<ProtocolProviderService, List<String>> callees,
Call call)
{
new InviteToCrossProtocolConferenceCallThread(provider, callee, call).
new InviteToCrossProtocolConferenceCallThread(callees, call).
start();
}
/**
* Create a call to the given list of contacts.
*
* @param callees the list of contacts to invite
*/
public static void createCrossProtocolConferenceCall(
Map<ProtocolProviderService, List<String>> callees)
{
new CreateCrossProtocolConferenceCallThread(callees).start();
}
/**
* Puts on or off hold the given <tt>callPeer</tt>.
* @param callPeer the peer to put on/off hold
@ -1103,12 +1135,25 @@ public void run()
if (telephonyOpSet == null)
return;
String callString = null;
if(contact != null)
callString = contact.getAddress();
else if(stringContact != null)
callString = stringContact;
if(ConfigurationManager.isNormalizePhoneNumber())
{
String normalizedContact[] = new String[1];
normalizedContact[0] = callString;
normalizePhoneNumbers(normalizedContact);
callString = normalizedContact[0];
}
try
{
if (contact != null)
telephonyOpSet.createCall(contact);
else if (stringContact != null)
telephonyOpSet.createCall(stringContact);
telephonyOpSet.createCall(callString);
}
catch (Throwable exception)
{
@ -1299,9 +1344,18 @@ private static class AnswerCallThread
{
private final Call call;
private final Call existingCall;
public AnswerCallThread(Call call)
{
this.call = call;
this.existingCall = null;
}
public AnswerCallThread(Call call, Call existingCall)
{
this.call = call;
this.existingCall = existingCall;
}
@Override
@ -1309,6 +1363,22 @@ public void run()
{
ProtocolProviderService pps = call.getProtocolProvider();
Iterator<? extends CallPeer> peers = call.getCallPeers();
CallGroup group = null;
if(existingCall != null)
{
if(existingCall.getCallGroup() == null)
{
group = new CallGroup();
group.addCall(existingCall);
}
else
{
group = existingCall.getCallGroup();
}
if(call.getCallGroup() == null && group != null)
group.addCall(call);
}
while (peers.hasNext())
{
@ -1408,6 +1478,11 @@ public void run()
Throwable exception = null;
if (ConfigurationManager.isNormalizePhoneNumber())
{
normalizePhoneNumbers(callees);
}
try
{
confOpSet.createConfCall(callees);
@ -1472,6 +1547,11 @@ public void run()
if (confOpSet == null)
return;
if (ConfigurationManager.isNormalizePhoneNumber())
{
normalizePhoneNumbers(callees);
}
for (String callee : callees)
{
Throwable exception = null;
@ -1516,19 +1596,16 @@ public void run()
private static class InviteToCrossProtocolConferenceCallThread
extends Thread
{
private final ProtocolProviderService provider;
private final String callee;
private final Map<ProtocolProviderService, List<String>>
callees;
private final Call call;
public InviteToCrossProtocolConferenceCallThread(
ProtocolProviderService provider,
String callee,
Map<ProtocolProviderService, List<String>> callees,
Call call)
{
this.provider = provider;
this.callee = callee;
this.callees = callees;
this.call = call;
}
@ -1547,37 +1624,117 @@ public void run()
group = call.getCallGroup();
}
OperationSetBasicTelephony<?> opSetTelephony =
provider.getOperationSet(OperationSetBasicTelephony.class);
if(opSetTelephony != null)
for(Map.Entry<ProtocolProviderService, List<String>> entry :
callees.entrySet())
{
Exception exception = null;
ProtocolProviderService provider = entry.getKey();
List<String> contacts = entry.getValue();
try
{
Call c = opSetTelephony.createCall(callee, group);
group.addCall(c);
}
catch(Exception e)
OperationSetBasicTelephony<?> opSetTelephony =
provider.getOperationSet(OperationSetBasicTelephony.class);
if(opSetTelephony != null)
{
exception = e;
logger.info("Failed to call " + callee, e);
OperationSetTelephonyConferencing opSetConf =
provider.getOperationSet(
OperationSetTelephonyConferencing.class);
String[] contactAddressStrings =
new String[contacts.size()];
contacts.toArray(contactAddressStrings);
if (ConfigurationManager.isNormalizePhoneNumber())
{
normalizePhoneNumbers(contactAddressStrings);
}
try
{
opSetConf.createConfCall(contactAddressStrings, group);
}
catch(Exception exception)
{
logger
.error("Failed to invite callees",
exception);
new ErrorDialog(
null,
GuiActivator
.getResources()
.getI18NString("service.gui.ERROR"),
exception.getMessage(),
ErrorDialog.ERROR)
.showDialog();
}
}
}
}
}
if (exception != null)
/**
* Invites a list of callees to a conference call.
*/
private static class CreateCrossProtocolConferenceCallThread
extends Thread
{
private final Map<ProtocolProviderService, List<String>>
callees;
public CreateCrossProtocolConferenceCallThread(
Map<ProtocolProviderService, List<String>> callees)
{
this.callees = callees;
}
@Override
public void run()
{
CallGroup group = new CallGroup();
for(Map.Entry<ProtocolProviderService, List<String>> entry :
callees.entrySet())
{
ProtocolProviderService provider = entry.getKey();
List<String> contacts = entry.getValue();
OperationSetBasicTelephony<?> opSetTelephony =
provider.getOperationSet(OperationSetBasicTelephony.class);
if(opSetTelephony != null)
{
logger
.error("Failed to invite callee: " + callee, exception);
OperationSetTelephonyConferencing opSetConf =
provider.getOperationSet(
OperationSetTelephonyConferencing.class);
new ErrorDialog(
null,
GuiActivator
.getResources()
.getI18NString("service.gui.ERROR"),
exception.getMessage(),
ErrorDialog.ERROR)
.showDialog();
String[] contactAddressStrings =
new String[contacts.size()];
contacts.toArray(contactAddressStrings);
if (ConfigurationManager.isNormalizePhoneNumber())
{
normalizePhoneNumbers(contactAddressStrings);
}
try
{
opSetConf.createConfCall(contactAddressStrings, group);
}
catch(Exception exception)
{
logger
.error("Failed to invite callees",
exception);
new ErrorDialog(
null,
GuiActivator
.getResources()
.getI18NString("service.gui.ERROR"),
exception.getMessage(),
ErrorDialog.ERROR)
.showDialog();
}
}
}
}
@ -1608,6 +1765,8 @@ public void run()
for(Call c : calls)
{
peers = c.getCallPeers();
if(!peers.hasNext())
return;
CallPeer peer = peers.next();
OperationSetBasicTelephony<?> telephony
= peer.getCall().getProtocolProvider().
@ -1832,4 +1991,34 @@ private static boolean showDesktopSharingWarning()
return true;
}
/**
* Normalizes the phone numbers (if any) in a list of <tt>String</tt>s.
*
* @param callees list of contact addresses or phone numbers
*/
private static void normalizePhoneNumbers(String callees[])
{
PhoneNumberI18nService phoneNumberService =
GuiActivator.getPhoneNumberService();
for(int i = 0 ; i < callees.length ; i++)
{
if (!StringUtils.containsLetters(callees[i]) &&
GuiActivator.getPhoneNumberService().isPhoneNumber(callees[i]))
{
String addr = callees[i];
if(phoneNumberService.isPhoneNumber(addr))
{
addr = phoneNumberService.normalize(addr);
}
else
{
addr = StringUtils.concatenateWords(callees[i]);
}
callees[i] = addr;
}
}
}
}

@ -30,6 +30,11 @@
public class CallTransferHandler
extends ExtendedTransferHandler
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The data flavor used when transferring <tt>UIContact</tt>s.
*/
@ -132,6 +137,8 @@ public boolean importData(JComponent comp, Transferable t)
OperationSetBasicTelephony.class).iterator();
String callee = null;
ProtocolProviderService provider = null;
while (contactDetails.hasNext())
{
UIContactDetail detail = contactDetails.next();
@ -141,14 +148,24 @@ public boolean importData(JComponent comp, Transferable t)
OperationSetBasicTelephony.class);
if (detailProvider != null
&& detailProvider.equals(callProvider))
/*&& detailProvider.equals(callProvider)*/)
{
callee = detail.getAddress();
provider = detailProvider;
break;
}
}
if (callee != null)
{
CallManager.inviteToConferenceCall(
new String[]{callee}, call);
Map<ProtocolProviderService, List<String>> callees =
new HashMap<ProtocolProviderService, List<String>>();
List<String> lst = new ArrayList<String>();
lst.add(callee);
callees.put(provider, lst);
CallManager.inviteToCrossProtocolConferenceCall(
callees, call);
return true;
}

@ -51,13 +51,15 @@ public ChooseCallAccountDialog(
.getI18NString("service.gui.CALL_VIA"),
GuiActivator.getResources().getI18NString(
"service.gui.CHOOSE_ACCOUNT"),
GuiActivator.getAccounts(providers), false);
GuiActivator.getAccounts(providers));
this.contactAddress = contactAddress;
this.opSetClass = opSetClass;
getAccountsCombo().setRenderer(new DefaultListCellRenderer()
{
private static final long serialVersionUID = 0L;
public Component getListCellRendererComponent(
JList jlist, Object obj, int i,
boolean flag, boolean flag1)
@ -113,6 +115,13 @@ else if (opSetClass.equals(
}
}
/**
* Indicates that the conference call button has been pressed.
*/
public void mergeCallButtonPressed()
{
}
/**
* Disposes the dialog when the hangup button is pressed.
*/

@ -32,6 +32,11 @@ public abstract class PreCallDialog
*/
private static final String CALL_BUTTON = "CallButton";
/**
* The conference call button name.
*/
private static final String CONF_CALL_BUTTON = "ConfCallButton";
/**
* The call button name.
*/
@ -52,6 +57,12 @@ public abstract class PreCallDialog
*/
private SIPCommButton callButton;
/**
* Conference call button to answer the call in an existing call or
* conference.
*/
private SIPCommButton mergeCallButton;
/**
* Video call button.
*/
@ -92,16 +103,35 @@ public abstract class PreCallDialog
*/
private boolean video = false;
/**
* If the call should be answered in an existing call.
*/
private boolean mergeCall = false;
/**
* Creates an instanceof <tt>PreCallDialog</tt> by specifying the dialog
* title.
*
* @param title the title of the dialog
* @param video if it is a video call
* @param existingCall true to answer call in an existing call
*/
public PreCallDialog(String title, boolean video, boolean existingCall)
{
this(title, null, null, video, existingCall);
}
/**
* Creates an instanceof <tt>PreCallDialog</tt> by specifying the dialog
* title and the text to show.
*
* @param title the title of the dialog
* @param text the text to show
* @param accounts the list of accounts to choose from
*/
public PreCallDialog(String title, boolean video)
public PreCallDialog(String title, String text, Object[] accounts)
{
this(title, null, null, video);
this(title, text, accounts, false, false);
}
/**
@ -112,13 +142,15 @@ public PreCallDialog(String title, boolean video)
* @param text the text to show
* @param accounts the list of accounts to choose from
* @param video if it is a video call
* @param existingCall true to answer call in an existing call
*/
public PreCallDialog(String title, String text, Object[] accounts,
boolean video)
boolean video, boolean existingCall)
{
preCallWindow = createPreCallWindow(title, text, accounts);
this.video = video;
this.mergeCall = existingCall;
// check whether we have device enabled for capturing(sending)
this.video = video && GuiActivator.getMediaService().getDefaultDevice(
@ -210,6 +242,12 @@ private void initComponents()
callButton = new SIPCommButton(
ImageLoader.getImage(ImageLoader.CALL_BUTTON_BG));
if(mergeCall)
{
mergeCallButton = new SIPCommButton(
ImageLoader.getImage(ImageLoader.MERGE_CALL_BUTTON_BG));
}
if(video)
{
videoCallButton = new SIPCommButton(
@ -227,6 +265,13 @@ private void initComponents()
hangupButton.setName(HANGUP_BUTTON);
callButton.addActionListener(this);
if(mergeCall)
{
mergeCallButton.setName(CONF_CALL_BUTTON);
mergeCallButton.addActionListener(this);
}
hangupButton.addActionListener(this);
if(video)
@ -283,6 +328,14 @@ private void initComponents()
constraints.gridheight = 0;
buttonsPanel.add(callButton, constraints);
if(mergeCall)
{
constraints.gridx++;
buttonsPanel.add(Box.createHorizontalStrut(HGAP));
constraints.gridx++;
buttonsPanel.add(mergeCallButton, constraints);
}
if(video)
{
constraints.gridx++;
@ -392,6 +445,10 @@ public void actionPerformed(ActionEvent e)
{
callButtonPressed();
}
else if (buttonName.equals(CONF_CALL_BUTTON))
{
mergeCallButtonPressed();
}
else if (buttonName.equals(VIDEO_CALL_BUTTON))
{
videoCallButtonPressed();
@ -409,6 +466,11 @@ else if (buttonName.equals(HANGUP_BUTTON))
*/
public abstract void callButtonPressed();
/**
* Indicates that the conference call button has been pressed.
*/
public abstract void mergeCallButtonPressed();
/**
* Indicates that the hangup button has been pressed.
*/

@ -42,15 +42,17 @@ public class ReceivedCallDialog
*
* @param call The associated with this dialog incoming call.
* @param video if the call is a video call
* @param existingCall true to answer the call in an existing call (thus
* obtaining a conference call)
*/
public ReceivedCallDialog(Call call, boolean video)
public ReceivedCallDialog(Call call, boolean video, boolean existingCall)
{
super(GuiActivator.getResources()
.getSettingsString("service.gui.APPLICATION_NAME")
+ " "
+ GuiActivator.getResources()
.getI18NString("service.gui.INCOMING_CALL_STATUS")
.toLowerCase(), video);
.toLowerCase(), video, existingCall);
this.incomingCall = call;
@ -187,6 +189,16 @@ public void callButtonPressed()
CallManager.answerCall(incomingCall);
}
/**
* Answers the call in an existing call when the existing call
* button has been pressed.
*/
@Override
public void mergeCallButtonPressed()
{
CallManager.answerCallInFirstExistingCall(incomingCall);
}
/**
* Answers the call when the call button has been pressed.
*/
@ -241,5 +253,4 @@ private String getPeerDisplayAddress(CallPeer peer)
return peerAddress;
}
}

@ -46,11 +46,6 @@ public class CallPeerMenu
private final JMenuItem holdMenuItem= new JMenuItem(onHoldText);
private final String muteText = GuiActivator.getResources()
.getI18NString("service.gui.MUTE");
private final String unmuteText = GuiActivator.getResources()
.getI18NString("service.gui.UNMUTE");
/**
* Creates a <tt>CallPeerActionMenuBar</tt> by specifying the associated
* <tt>callPeer</tt>.

@ -82,11 +82,6 @@ public class ConferenceCallPanel
private final List<Container> videoContainers
= new LinkedList<Container>();
/**
* The video handler.
*/
private UIVideoHandler videoHandler;
/**
* The implementation of the routine which scrolls this scroll pane to its
* bottom.
@ -170,7 +165,7 @@ public ConferenceCallPanel(CallPanel callPanel, Call c)
/**
* Initializes a new <tt>VideoContainer</tt> instance which is to contain
* the visual/video <tt>Component</tt>s of {@link #call}.
* the visual/video <tt>Component</tt>s of {@link #call}.
*/
private void addVideoContainer()
{
@ -327,7 +322,7 @@ public void addCallPeerPanel(CallPeer peer)
ConferenceCallPeerRenderer confPeerRenderer;
videoHandler
UIVideoHandler videoHandler
= new UIVideoHandler(peer, this, videoContainers);
videoHandler.addVideoListener();
@ -392,6 +387,8 @@ public void removeCallPeerPanel(CallPeer peer)
if (confPeerRenderer == null)
return;
confPeerRenderer.getVideoHandler().removeRemoteControlListener();
// first remove the listeners as after removing the panel
// we may still receive sound level indicators and there are
// missing ui components leading to exception

@ -9,6 +9,7 @@
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List; //disambiguation
import javax.swing.*;
@ -33,10 +34,14 @@ public class ConferenceInviteDialog
*/
private static final long serialVersionUID = 0L;
private final JComboBox accountSelectorBox = new JComboBox();
private Object lastSelectedAccount;
/**
* The account selector box.
*/
private ProtocolProviderSelectorBox accountBox;
/**
* The call.
*/
private final Call call;
/**
@ -52,79 +57,25 @@ public ConferenceInviteDialog(Call call)
this.call = call;
JLabel accountSelectorLabel = new JLabel(
GuiActivator.getResources().getI18NString("service.gui.CALL_VIA"));
TransparentPanel accountSelectorPanel
= new TransparentPanel(new BorderLayout());
accountSelectorPanel.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5));
accountSelectorPanel.add(accountSelectorLabel, BorderLayout.WEST);
accountSelectorPanel.add(accountSelectorBox, BorderLayout.CENTER);
// Initialize the account selector box.
this.initAccountListData();
// init the list, as we check whether features are supported
// it may take some time if we have too much contacts
new Thread(new Runnable()
{
public void run()
SwingUtilities.invokeLater(
new Runnable()
{
// Initialize the list of contacts to select from.
initContactListData(
(ProtocolProviderService) accountSelectorBox
.getSelectedItem());
}
}).start();
this.getContentPane().add(accountSelectorPanel, BorderLayout.NORTH);
this.accountSelectorBox.setRenderer(new DefaultListCellRenderer()
{
private static final long serialVersionUID = 0L;
public Component getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected,
boolean cellHasFocus)
{
ProtocolProviderService protocolProvider
= (ProtocolProviderService) value;
if (protocolProvider != null)
public void run()
{
this.setText(
protocolProvider.getAccountID().getDisplayName());
this.setIcon(
ImageLoader.getAccountStatusImage(protocolProvider));
// Initialize the list of contacts to select from.
initContactListData();
}
});
return this;
}
});
this.accountSelectorBox.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Object accountSelectorBoxSelectedItem
= accountSelectorBox.getSelectedItem();
if (lastSelectedAccount == null
|| !lastSelectedAccount
.equals(accountSelectorBoxSelectedItem))
{
lastSelectedAccount = accountSelectorBoxSelectedItem;
removeAllSelectedContacts();
initContactListData(
(ProtocolProviderService) accountSelectorBox
.getSelectedItem());
}
}
});
this.getContentPane().add(accountSelectorPanel, BorderLayout.NORTH);
this.addInviteButtonListener(new ActionListener()
{
@ -133,19 +84,7 @@ public void actionPerformed(ActionEvent e)
if (getSelectedMetaContacts() != null
|| getSelectedStrings() != null)
{
ProtocolProviderService selectedProvider
= (ProtocolProviderService) accountSelectorBox
.getSelectedItem();
if (selectedProvider == null)
return;
inviteContacts(selectedProvider);
// Store the last used account in order to pre-select it
// next time.
ConfigurationManager.setLastCallConferenceProvider(
selectedProvider);
inviteContacts();
dispose();
}
@ -180,42 +119,29 @@ public ConferenceInviteDialog()
*/
private void initAccountListData()
{
// If we have a specified call, we'll have only one provider in the
// box.
if (call != null)
{
accountSelectorBox.addItem(call.getProtocolProvider());
accountSelectorBox.setEnabled(false);
}
else
{
Iterator<ProtocolProviderService> protocolProviders
= GuiActivator.getUIService()
.getMainFrame().getProtocolProviders();
Iterator<ProtocolProviderService> protocolProviders
= GuiActivator.getUIService()
.getMainFrame().getProtocolProviders();
while(protocolProviders.hasNext())
List<ProtocolProviderService> provs =
new ArrayList<ProtocolProviderService>();
while(protocolProviders.hasNext())
{
ProtocolProviderService protocolProvider
= protocolProviders.next();
OperationSet opSet
= protocolProvider
.getOperationSet(
OperationSetTelephonyConferencing.class);
if (opSet != null && protocolProvider.isRegistered())
{
ProtocolProviderService protocolProvider
= protocolProviders.next();
OperationSet opSet
= protocolProvider
.getOperationSet(
OperationSetTelephonyConferencing.class);
if (opSet != null && protocolProvider.isRegistered())
{
accountSelectorBox.addItem(protocolProvider);
}
provs.add(protocolProvider);
}
}
// Obtain the last conference provider used.
ProtocolProviderService lastConfProvider
= ConfigurationManager.getLastCallConferenceProvider();
// Try to select the last used account if it's available.
if (lastConfProvider != null)
accountSelectorBox.setSelectedItem(lastConfProvider);
if(accountBox == null)
accountBox = new ProtocolProviderSelectorBox(provs.iterator());
}
/**
@ -224,7 +150,7 @@ private void initAccountListData()
* @param protocolProvider the protocol provider from which to initialize
* the contact list data
*/
private void initContactListData(ProtocolProviderService protocolProvider)
private void initContactListData()
{
// re-init list.
this.removeAllMetaContacts();
@ -232,30 +158,40 @@ private void initContactListData(ProtocolProviderService protocolProvider)
MetaContactListService metaContactListService
= GuiActivator.getContactListService();
Iterator<MetaContact> contactListIter = metaContactListService
.findAllMetaContactsForProvider(protocolProvider);
Iterator<ProtocolProviderService> protocolProviders
= GuiActivator.getUIService()
.getMainFrame().getProtocolProviders();
while (contactListIter.hasNext())
while(protocolProviders.hasNext())
{
MetaContact metaContact = contactListIter.next();
ProtocolProviderService protocolProvider = protocolProviders.next();
Iterator<MetaContact> contactListIter = metaContactListService
.findAllMetaContactsForProvider(protocolProvider);
if (!containsContact(metaContact))
while (contactListIter.hasNext())
{
if (metaContact.getDefaultContact(
OperationSetBasicTelephony.class) != null)
addMetaContact(metaContact);
MetaContact metaContact = contactListIter.next();
if (!containsContact(metaContact))
{
if (metaContact.getDefaultContact(
OperationSetBasicTelephony.class) != null)
addMetaContact(metaContact);
}
}
}
}
/**
* Invites the contacts to the chat conference.
* @param selectedProvider the selected protocol provider
*/
private void inviteContacts(ProtocolProviderService selectedProvider)
private void inviteContacts()
{
java.util.List<String> selectedContactAddresses
= new ArrayList<String>();
ProtocolProviderService selectedProvider = null;
Map<ProtocolProviderService, List<String>> selectedProviderCallees =
new HashMap<ProtocolProviderService, List<String>>();
List<String> callees = null;
// Obtain selected contacts.
Enumeration<MetaContact> selectedContacts = getSelectedMetaContacts();
@ -267,48 +203,65 @@ private void inviteContacts(ProtocolProviderService selectedProvider)
MetaContact metaContact
= selectedContacts.nextElement();
Iterator<Contact> contactsIter = metaContact
.getContactsForProvider(selectedProvider);
Iterator<Contact> contactsIter = metaContact.getContacts();
// We invite the first protocol contact that corresponds to the
// invite provider.
if (contactsIter.hasNext())
{
Contact inviteContact = contactsIter.next();
selectedContactAddresses.add(inviteContact.getAddress());
selectedProvider = inviteContact.getProtocolProvider();
if(selectedProviderCallees.get(selectedProvider) != null)
{
callees = selectedProviderCallees.get(selectedProvider);
}
else
{
callees = new ArrayList<String>();
}
callees.add(inviteContact.getAddress());
selectedProviderCallees.put(selectedProvider, callees);
}
}
}
// Obtain selected strings.
Enumeration<String> selectedStrings = getSelectedStrings();
Enumeration<ContactWithProvider> selectedContactWithProvider =
getSelectedContactsWithProvider();
if (selectedStrings != null)
if (selectedContactWithProvider != null)
{
while (selectedStrings.hasMoreElements())
while (selectedContactWithProvider.hasMoreElements())
{
selectedContactAddresses.add(selectedStrings.nextElement());
}
}
ContactWithProvider c =
selectedContactWithProvider.nextElement();
selectedProvider = c.getProvider();
// Invite all selected.
String[] contactAddressStrings = null;
if (selectedContactAddresses.size() > 0)
{
contactAddressStrings = new String[selectedContactAddresses.size()];
contactAddressStrings
= selectedContactAddresses.toArray(contactAddressStrings);
if(selectedProviderCallees.get(selectedProvider) != null)
{
callees = selectedProviderCallees.get(selectedProvider);
}
else
{
callees = new ArrayList<String>();
}
callees.add(c.getAddress());
selectedProviderCallees.put(selectedProvider, callees);
}
}
if (call != null)
if(call != null)
{
CallManager.inviteToConferenceCall(contactAddressStrings, call);
CallManager.inviteToCrossProtocolConferenceCall(
selectedProviderCallees, call);
}
else
{
CallManager.createConferenceCall(
contactAddressStrings, selectedProvider);
CallManager.createCrossProtocolConferenceCall(
selectedProviderCallees);
}
}
@ -339,34 +292,118 @@ private boolean containsContact(MetaContact metaContact)
}
/**
* Returns <tt>true</tt> if <tt>Contact</tt> supports the specified
* <tt>OperationSet</tt>, <tt>false</tt> otherwise.
* Moves a string from left to right.
*/
@Override
protected void moveStringFromLeftToRight()
{
String newContactText = newContactField.getText();
ContactWithProvider c = new ContactWithProvider(
newContactText, accountBox.getSelectedProvider());
if (newContactText != null && newContactText.length() > 0)
selectedContactListModel.addElement(c);
newContactField.setText("");
}
/**
* Returns an enumeration of the list of selected Strings.
* @return an enumeration of the list of selected Strings
*/
public Enumeration<ContactWithProvider> getSelectedContactsWithProvider()
{
if (selectedContactListModel.getSize() == 0)
return null;
Vector<ContactWithProvider> selectedStrings =
new Vector<ContactWithProvider>();
Enumeration<?> selectedContacts = selectedContactListModel.elements();
while(selectedContacts.hasMoreElements())
{
Object contact = selectedContacts.nextElement();
if (contact instanceof ContactWithProvider)
selectedStrings.add((ContactWithProvider)contact);
}
return selectedStrings.elements();
}
/**
* Get the <tt>newContact</tt> component.
*
* @return the <tt>newContact</tt> component.
*/
@Override
public JComponent getNewContactPanel()
{
initAccountListData();
JPanel panel = new TransparentPanel(new BorderLayout());
panel.add(super.getNewContactPanel(), BorderLayout.CENTER);
panel.add(accountBox, BorderLayout.WEST);
return panel;
}
/**
* Contact with the provider to call him.
*
* @param contact contact to check
* @param opSet <tt>OperationSet</tt> to search for
* @return Returns <tt>true</tt> if <tt>Contact</tt> supports the specified
* <tt>OperationSet</tt>, <tt>false</tt> otherwise.
* @author Sebastien Vincent
*/
private boolean hasContactCapabilities(
Contact contact, Class<? extends OperationSet> opSet)
private class ContactWithProvider
{
OperationSetContactCapabilities capOpSet =
contact.getProtocolProvider().
getOperationSet(OperationSetContactCapabilities.class);
/**
* The provider.
*/
private final ProtocolProviderService provider;
/**
* The contact.
*/
private final String contact;
/**
* Constructor.
*
* @param contact the contact
* @param provider the provider
*/
public ContactWithProvider(String contact,
ProtocolProviderService provider)
{
this.contact = contact;
this.provider = provider;
}
if (capOpSet == null)
/**
* Returns the contact
*
* @return the contact
*/
public String getAddress()
{
// assume contact has OpSet capabilities
return true;
return contact;
}
else
/**
* Returns the provider.
*
* @return the provider
*/
public ProtocolProviderService getProvider()
{
if(capOpSet.getOperationSet(contact, opSet) != null)
{
return true;
}
return provider;
}
return false;
/**
* Returns <tt>String</tt> representation.
*
* @return <tt>String</tt> representation
*/
@Override
public String toString()
{
return contact;
}
}
}

@ -0,0 +1,256 @@
/*
* 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.gui.main.call.conference;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
import net.java.sip.communicator.util.swing.*;
/**
* The <tt>ProtocolProviderSelectorBox</tt> represents the call via menu in the
* chat window. The menu contains all protocol providers.
*
* @author Yana Stamcheva
* @author Adam Netocny
* @author Sebastien Vincent
*/
public class ProtocolProviderSelectorBox
extends SIPCommMenuBar
implements ActionListener,
Skinnable
{
/**
* The logger for this class.
*/
private static final Logger logger
= Logger.getLogger(ProtocolProviderSelectorBox.class);
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The providers list associated with its <tt>JMenuItem</tt>.
*/
private final Map<ProtocolProviderService, JMenuItem> providerMenuItems =
new Hashtable<ProtocolProviderService, JMenuItem>();
/**
* The menu.
*/
private final SIPCommMenu menu = new SelectorMenu();
/**
* The last selected provider.
*/
private ProtocolProviderService lastSelectedProvider = null;
/**
* Creates an instance of <tt>ProtocolProviderSelectorBox</tt>.
*
* @param providers list of <tt>ProtocolProviderService</tt>
*/
public ProtocolProviderSelectorBox(
Iterator<ProtocolProviderService> providers)
{
setPreferredSize(new Dimension(30, 28));
setMaximumSize(new Dimension(30, 28));
setMinimumSize(new Dimension(30, 28));
this.menu.setPreferredSize(new Dimension(30, 45));
this.menu.setMaximumSize(new Dimension(30, 45));
this.add(menu);
this.setBorder(null);
this.menu.setBorder(null);
this.menu.setOpaque(false);
this.setOpaque(false);
// as a default disable the menu, it will be enabled as soon as we add
// a valid menu item
this.menu.setEnabled(false);
ProtocolProviderService defaultProvider = null;
while(providers.hasNext())
{
ProtocolProviderService provider = providers.next();
if(defaultProvider == null)
defaultProvider = provider;
addProtocolProviderService(provider);
}
setSelected(defaultProvider);
}
/**
* Sets the menu to enabled or disabled. The menu is enabled, as soon as it
* contains one or more items. If it is empty, it is disabled.
*/
private void updateEnableStatus()
{
this.menu.setEnabled(this.menu.getItemCount() > 0);
}
/**
* Adds the given provider to the "call via" menu.
* Only add those that support telephony.
*
* @param provider The provider to add.
*/
public void addProtocolProviderService(ProtocolProviderService provider)
{
if (provider.getOperationSet(OperationSetBasicTelephony.class) != null)
{
Image img = createProviderImage(provider);
JMenuItem menuItem = new JMenuItem(
"Via: " + provider.getAccountID().getDisplayName(),
new ImageIcon(img));
menuItem.addActionListener(this);
this.providerMenuItems.put(provider, menuItem);
this.menu.add(menuItem);
updateEnableStatus();
}
}
/**
* Removes the given provider from the "call via" menu. This method is
* used to update the "call via" menu when a protocol contact is moved or
* removed from the contact list.
*
* @param provider the provider to be removed
*/
public void removeProtocolProviderService(ProtocolProviderService provider)
{
this.menu.remove(providerMenuItems.get(provider));
this.providerMenuItems.remove(provider);
updateEnableStatus();
}
/**
* The listener of the provider selector box.
*
* @param e the <tt>ActionEvent</tt> that notified us
*/
public void actionPerformed(ActionEvent e)
{
JMenuItem menuItem = (JMenuItem) e.getSource();
for (Map.Entry<ProtocolProviderService, JMenuItem> providerMenuItem
: providerMenuItems.entrySet())
{
ProtocolProviderService provider = providerMenuItem.getKey();
if (providerMenuItem.getValue().equals(menuItem))
{
this.setSelected(provider, (ImageIcon) menuItem.getIcon());
return;
}
}
if (logger.isDebugEnabled())
logger.debug( "Could not find contact for menu item "
+ menuItem.getText() + ". contactsTable("
+ providerMenuItems.size()+") is : "
+ providerMenuItems);
}
/**
* Obtains the status icon for the given provider and
* adds to it the account index information.
*
* @param provider The provider for which to create the image.
* @return The indexed status image.
*/
public Image createProviderImage(ProtocolProviderService provider)
{
return
ImageLoader.getIndexedProtocolImage(
ImageUtils.getBytesInImage(
provider.getProtocolIcon().getIcon(
ProtocolIcon.ICON_SIZE_16x16)),
provider);
}
/**
* In the "call via" menu selects the given contact and sets the given icon
* to the "call via" menu button.
*
* @param provider the protocol provider
* @param icon the provider icon
*/
private void setSelected(ProtocolProviderService provider, ImageIcon icon)
{
lastSelectedProvider = provider;
SelectedObject selectedObject = new SelectedObject(icon, provider);
this.menu.setSelected(selectedObject);
}
/**
* Sets the selected protocol provider.
*
* @param provider the protocol provider to select
*/
public void setSelected(ProtocolProviderService provider)
{
this.setSelected(provider,
new ImageIcon(createProviderImage(provider)));
}
/**
* Returns the protocol menu.
*
* @return the protocol menu
*/
public SIPCommMenu getMenu()
{
return menu;
}
/**
* Returns the selected provider.
*
* @return the selected provider.
*/
public ProtocolProviderService getSelectedProvider()
{
return lastSelectedProvider;
}
private class SelectorMenu extends SIPCommMenu
{
private static final long serialVersionUID = 0L;
Image image = ImageLoader.getImage(ImageLoader.DOWN_ARROW_ICON);
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image,
getWidth() - image.getWidth(this) - 1,
(getHeight() - image.getHeight(this) - 1)/2,
this);
}
}
}

@ -34,6 +34,8 @@ public class ChatTransportSelectorBox
private static final Logger logger
= Logger.getLogger(ChatTransportSelectorBox.class);
private static final long serialVersionUID = 0L;
private final Map<ChatTransport, JMenuItem> transportMenuItems =
new Hashtable<ChatTransport, JMenuItem>();
@ -46,6 +48,7 @@ public class ChatTransportSelectorBox
/**
* Creates an instance of <tt>ChatTransportSelectorBox</tt>.
*
* @param chatPanel the chat panel
* @param chatSession the corresponding chat session
* @param selectedChatTransport the chat transport to select by default
*/
@ -88,10 +91,10 @@ public ChatTransportSelectorBox(ChatPanel chatPanel,
}
}
/*
/**
* Sets the menu to enabled or disabled. The menu is enabled, as soon as it
* contains one or more items. If it is empty, it is disabled.
*/
*/
private void updateEnableStatus()
{
this.menu.setEnabled(this.menu.getItemCount() > 0);
@ -299,6 +302,8 @@ private boolean containsOtherOnlineContacts(ChatTransport chatTransport)
private class SelectorMenu extends SIPCommMenu
{
private static final long serialVersionUID = 0L;
Image image = ImageLoader.getImage(ImageLoader.DOWN_ARROW_ICON);
public void paintComponent(Graphics g)

@ -35,6 +35,11 @@ public class ContactListCellRenderer
Icon,
Skinnable
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The avatar icon height.
*/
@ -178,7 +183,7 @@ public ContactListCellRenderer()
* @param index the index of the current cell in the source list
* @param isSelected indicates if this cell is selected
* @param cellHasFocus indicates if this cell is focused
*
*
* @return this panel
*/
public Component getListCellRendererComponent(JList list, Object value,
@ -277,7 +282,7 @@ else if (value instanceof MetaContactGroup)
// We have no photo icon for groups.
this.rightLabel.setIcon(null);
this.rightLabel.setText( groupItem.countOnlineChildContacts()
this.rightLabel.setText( groupItem.countOnlineChildContacts()
+ "/" + groupItem.countChildContacts());
this.isLeaf = false;
@ -288,6 +293,12 @@ else if (value instanceof String)
this.nameLabel.setText((String) value);
this.nameLabel.setFont(this.getFont().deriveFont(Font.PLAIN));
}
else
{
this.setPreferredSize(new Dimension(20, 30));
this.nameLabel.setText(value.toString());
this.nameLabel.setFont(this.getFont().deriveFont(Font.PLAIN));
}
this.isSelected = isSelected;
@ -297,7 +308,7 @@ else if (value instanceof String)
/**
* Gets the avatar of a specific <tt>MetaContact</tt> in the form of an
* <tt>ImageIcon</tt> value.
*
*
* @param metaContact the <tt>MetaContact</tt> to retrieve the avatar of
* @return an <tt>ImageIcon</tt> which represents the avatar of the
* specified <tt>MetaContact</tt>
@ -309,7 +320,7 @@ private ImageIcon getAvatar(MetaContact metaContact)
// Try to get the avatar from the cache.
Object[] avatarCache = (Object[]) metaContact.getData(AVATAR_DATA_KEY);
if ((avatarCache != null) && (avatarCache[0] == avatarBytes))
if ((avatarCache != null) && (avatarCache[0] == avatarBytes))
avatar = (ImageIcon) avatarCache[1];
// If the avatar isn't available or it's not up-to-date, create it.
@ -459,7 +470,7 @@ public void paintIcon(Component c, Graphics g, int x, int y)
getIconWidth() - 1, getIconHeight() - 1,
10, 10);
// Indent component content from the border.
// Indent component content from the border.
g2.translate(x + 5, y + 5);
// Paint component.

@ -29,7 +29,7 @@
/**
* The <tt>FileMenu</tt> is a menu in the main application menu bar that
* contains "New account".
*
*
* @author Yana Stamcheva
* @author Lubomir Marinov
* @author Adam Netocny
@ -40,6 +40,11 @@ public class ToolsMenu
PluginComponentListener,
Skinnable
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* Local logger.
*/
@ -124,7 +129,7 @@ private void initPluginComponents()
GuiActivator.getUIService().addPluginComponentListener(this);
}
/**
* Handles the <tt>ActionEvent</tt> when one of the menu items is selected.
* @param e the <tt>ActionEvent</tt> that notified us

@ -263,6 +263,12 @@ public class ImageLoader
public static final ImageID CALL_BUTTON_BG
= new ImageID("service.gui.buttons.CALL_BUTTON_BG");
/**
* The call button image.
*/
public static final ImageID MERGE_CALL_BUTTON_BG
= new ImageID("service.gui.buttons.MERGE_CALL_BUTTON_BG");
/**
* The video call button image.
*/

@ -30,6 +30,8 @@ public class InviteDialog
extends SIPCommDialog
implements Skinnable
{
private static final long serialVersionUID = 0L;
private final JTextArea reasonArea = new JTextArea();
private final JButton inviteButton = new JButton(
@ -40,10 +42,10 @@ public class InviteDialog
private final DefaultListModel contactListModel = new DefaultListModel();
private final DefaultListModel selectedContactListModel
protected final DefaultListModel selectedContactListModel
= new DefaultListModel();
private final SIPCommTextField newContactField
protected final SIPCommTextField newContactField
= new SIPCommTextField(GuiActivator.getResources()
.getI18NString("service.gui.OR_ENTER_PHONE_NUMBER"));
@ -199,7 +201,7 @@ public void focusGained(FocusEvent e)
TransparentPanel leftPanel = new TransparentPanel(new BorderLayout());
leftPanel.setBorder(SIPCommBorders.getRoundBorder());
leftPanel.add(contactListScrollPane);
leftPanel.add(newContactField, BorderLayout.SOUTH);
leftPanel.add(getNewContactPanel(), BorderLayout.SOUTH);
JPanel listPanel = new JPanel(new GridLayout(0, 2, 5, 5));
listPanel.setPreferredSize(new Dimension(400, 200));
@ -396,7 +398,7 @@ private void moveContactsFromLeftToRight(Object[] metaContacts)
/**
* Moves a string from left to right.
*/
private void moveStringFromLeftToRight()
protected void moveStringFromLeftToRight()
{
String newContactText = newContactField.getText();
@ -430,6 +432,8 @@ private void moveContactsFromRightToLeft(Object[] contacts)
private class MoveStringToRight
extends UIAction
{
private static final long serialVersionUID = 0L;
public void actionPerformed(ActionEvent e)
{
moveStringFromLeftToRight();
@ -444,4 +448,14 @@ public void loadSkin()
iconLabel.setIcon(new ImageIcon(
ImageLoader.getImage(ImageLoader.INVITE_DIALOG_ICON)));
}
/**
* Get the <tt>newContact</tt> component.
*
* @return the <tt>newContact</tt> component.
*/
public JComponent getNewContactPanel()
{
return newContactField;
}
}

@ -66,6 +66,20 @@ public OperationSetTelephonyConferencingGibberishImpl(
*/
public Call createConfCall(String[] callees)
throws OperationNotSupportedException
{
return createConfCall(callees, null);
}
/**
* Creates a conference call with the given list of <tt>callees</tt>
* @param callees the list of <tt>callees</tt> to invite in the call
* @param group the <tt>CallGroup</tt> or null
* @return the created call
* @throws OperationNotSupportedException indicates that the operation is
* not supported for the given <tt>callees</tt>.
*/
public Call createConfCall(String[] callees, CallGroup group)
throws OperationNotSupportedException
{
CallGibberishImpl newCall = new CallGibberishImpl(protocolProvider);

@ -199,8 +199,24 @@ public CallPeerGTalkImpl initiateGTalkSession(
}
}
}
parentOpSet.fireCallEvent(CallEvent.CALL_INITIATED, this);
// if this was the first peer we added in this call then the call is
// new and we also need to notify everyone of its creation.
if(getCallPeerCount() == 1 && getCallGroup() == null)
{
parentOpSet.fireCallEvent(CallEvent.CALL_INITIATED, this);
}
else if(getCallGroup() != null)
{
// only TelephonyConferencing OperationSet should know about it
CallEvent cEvent = new CallEvent(this,
CallEvent.CALL_INITIATED);
AbstractOperationSetTelephonyConferencing<?,?,?,?,?> opSet =
(AbstractOperationSetTelephonyConferencing<?,?,?,?,?>)
getProtocolProvider().getOperationSet(
OperationSetTelephonyConferencing.class);
if(opSet != null)
opSet.outgoingCallCreated(cEvent);
}
}
CallPeerMediaHandlerGTalkImpl mediaHandler

@ -246,7 +246,7 @@ else if(c.getName().equals(MediaType.VIDEO.toString()))
// if this was the first peer we added in this call then the call is
// new and we also need to notify everyone of its creation.
if(this.getCallPeerCount() == 1)
if(this.getCallPeerCount() == 1 && getCallGroup() == null)
parentOpSet.fireCallEvent(CallEvent.CALL_RECEIVED, this,
directions);

@ -152,6 +152,7 @@ public Call createCall(String callee, CallGroup group)
if(callPeer.getCall() != call)
{
// We may have a Google Talk call here
callPeer.getCall().setCallGroup(group);
return callPeer.getCall();
}
@ -454,6 +455,7 @@ else if(di != null)
CallGTalkImpl callGTalk = new CallGTalkImpl(this);
MediaUseCase useCase = call.getMediaUseCase();
boolean isVideo = call.isLocalVideoAllowed(useCase);
callGTalk.setCallGroup(call.getCallGroup());
callGTalk.setLocalVideoAllowed(isVideo, useCase);
peer = callGTalk.initiateGTalkSession(fullCalleeURI,

@ -301,6 +301,32 @@ private IQ getConferenceInfo(CallPeerJabberImpl callPeer, int version)
{
CoinIQ iq = new CoinIQ();
CallJabberImpl call = callPeer.getCall();
List<CallPeer> crossPeers = new ArrayList<CallPeer>();
Iterator<CallPeer> crossProtocolCallPeerIter =
call.getCrossProtocolCallPeers();
while (crossProtocolCallPeerIter.hasNext())
{
MediaAwareCallPeer<?,?,?> crossPeer =
(MediaAwareCallPeer<?,?,?>)crossProtocolCallPeerIter.next();
Iterator<CallPeerJabberImpl> it = call.getCallPeers();
boolean found = false;
while(it.hasNext())
{
if(it.next().getAddress().equals(crossPeer.getAddress()))
{
found = true;
break;
}
}
if(found)
continue;
if(!crossPeers.contains(crossPeer))
crossPeers.add(crossPeer);
}
iq.setFrom(call.getProtocolProvider().getOurJID());
iq.setTo(callPeer.getAddress());
@ -319,7 +345,7 @@ private IQ getConferenceInfo(CallPeerJabberImpl callPeer, int version)
// conference-state
StatePacketExtension state = new StatePacketExtension();
state.setUserCount(call.getCallPeerCount() + 1 +
call.getCrossProtocolCallPeerCount());
crossPeers.size());
iq.addExtension(state);
// users
@ -353,13 +379,11 @@ private IQ getConferenceInfo(CallPeerJabberImpl callPeer, int version)
users.addChildExtension(ext);
}
Iterator<CallPeer> crossProtocolCallPeerIter =
call.getCrossProtocolCallPeers();
while (crossProtocolCallPeerIter.hasNext())
for(CallPeer cp : crossPeers)
{
UserPacketExtension ext = getUser(
(MediaAwareCallPeer<?,?,?>)crossProtocolCallPeerIter.next());
MediaAwareCallPeer<?,?,?> crossPeer =
(MediaAwareCallPeer<?,?,?>)cp;
UserPacketExtension ext = getUser(crossPeer);
users.addChildExtension(ext);
}
@ -444,7 +468,8 @@ protected CallPeer inviteCalleeToCall(
while (callPeerIter.hasNext())
{
CallPeerJabberImpl callPeer = callPeerIter.next();
callPeer.sendCoinSessionInfo(true);
if(callPeer.getState() == CallPeerState.CONNECTED)
callPeer.sendCoinSessionInfo(true);
}
}
@ -559,6 +584,7 @@ private void handleCoin(CoinIQ coinIQ, CallPeerJabberImpl callPeer)
int conferenceMembersToRemoveCount = conferenceMembersToRemove.length;
UsersPacketExtension users = null;
Collection<PacketExtension> usersList = coinIQ.getExtensions();
boolean changed = false;
for(PacketExtension ext : usersList)
{
@ -671,7 +697,11 @@ private void handleCoin(CoinIQ coinIQ, CallPeerJabberImpl callPeer)
if (ssrc != null)
{
existingConferenceMember.setSSRC(Long.parseLong(ssrc));
long newSsrc = Long.parseLong(ssrc);
if(existingConferenceMember.getSSRC() != newSsrc)
changed = true;
existingConferenceMember.setSSRC(newSsrc);
}
if (addConferenceMember)
@ -695,5 +725,8 @@ private void handleCoin(CoinIQ coinIQ, CallPeerJabberImpl callPeer)
if (conferenceMemberToRemove != null)
callPeer.removeConferenceMember(conferenceMemberToRemove);
}
if(changed)
notifyAll(callPeer.getCall());
}
}

@ -428,7 +428,9 @@ public void callAdded(CallGroupEvent evt)
try
{
callPeer.sendReInvite();
if(callPeer.getDialog() != null &&
callPeer.getDialog().getState() == DialogState.CONFIRMED)
callPeer.sendReInvite();
}
catch(OperationFailedException e)
{

@ -319,6 +319,33 @@ private String getConferenceInfoXML(CallPeerSipImpl callPeer, int version)
StringBuffer xml = new StringBuffer();
CallSipImpl call = callPeer.getCall();
List<CallPeer> crossPeers = new ArrayList<CallPeer>();
Iterator<CallPeer> crossProtocolCallPeerIter =
call.getCrossProtocolCallPeers();
while (crossProtocolCallPeerIter.hasNext())
{
MediaAwareCallPeer<?,?,?> crossPeer =
(MediaAwareCallPeer<?,?,?>)crossProtocolCallPeerIter.next();
Iterator<CallPeerSipImpl> it = call.getCallPeers();
boolean found = false;
while(it.hasNext())
{
CallPeerSipImpl cpsip = it.next();
if(cpsip.getAddress().equals(crossPeer.getAddress()))
{
found = true;
break;
}
}
if(found)
continue;
if(!crossPeers.contains(crossPeer))
crossPeers.add(crossPeer);
}
xml.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
// <conference-info>
@ -380,14 +407,12 @@ private String getConferenceInfoXML(CallPeerSipImpl callPeer, int version)
while (callPeerIter.hasNext())
getUserXML(callPeerIter.next(), xml);
// cross-protocol CallPeer
Iterator<CallPeer> crossProtocolCallPeerIter =
call.getCrossProtocolCallPeers();
while (crossProtocolCallPeerIter.hasNext())
getUserXML(
(MediaAwareCallPeer<?,?,?>)crossProtocolCallPeerIter.next(),
xml);
for(CallPeer cp : crossPeers)
{
MediaAwareCallPeer<?,?,?> crossPeer =
(MediaAwareCallPeer<?,?,?>)cp;
getUserXML(crossPeer, xml);
}
// </users>
append(xml, "</", ELEMENT_USERS, ">");
@ -907,6 +932,7 @@ private void setConferenceInfoDocument(
ConferenceMember[] conferenceMembersToRemove
= callPeer.getConferenceMembers();
int conferenceMembersToRemoveCount = conferenceMembersToRemove.length;
boolean changed = false;
if (usersList.getLength() > 0)
{
@ -993,7 +1019,12 @@ else if (ELEMENT_ENDPOINT.equals(userChildName))
existingConferenceMember.setEndpointStatus(endpointStatus);
if (ssrc != null)
existingConferenceMember.setSSRC(Long.parseLong(ssrc));
{
long newSsrc = Long.parseLong(ssrc);
if(existingConferenceMember.getSSRC() != newSsrc)
changed = true;
existingConferenceMember.setSSRC(newSsrc);
}
if (addConferenceMember)
callPeer.addConferenceMember(existingConferenceMember);
@ -1015,6 +1046,9 @@ else if (ELEMENT_ENDPOINT.equals(userChildName))
if (conferenceMemberToRemove != null)
callPeer.removeConferenceMember(conferenceMemberToRemove);
}
if(changed)
notifyAll(callPeer.getCall());
}
/**

@ -29,6 +29,21 @@ public Call createConfCall(String[] callees)
throws OperationFailedException,
OperationNotSupportedException;
/**
* Creates a conference call with the specified callees as call peers.
*
* @param callees the list of addresses that we should call
* @param group the <tt>CallGroup</tt> or null
* @return the newly created conference call containing all CallPeers
* @throws OperationFailedException if establishing the conference call
* fails
* @throws OperationNotSupportedException if the provider does not have any
* conferencing features.
*/
public Call createConfCall(String[] callees, CallGroup group)
throws OperationFailedException,
OperationNotSupportedException;
/**
* Invites the callee represented by the specified uri to an already
* existing call. The difference between this method and createConfCall is

@ -18,7 +18,7 @@ public interface PhoneNumberI18nService
* Normalizes a <tt>String</tt> phone number by converting alpha characters
* to their respective digits on a keypad and then stripping non-digit
* characters.
*
*
* @param phoneNumber a <tt>String</tt> which represents a phone number to
* normalize
* @return a <tt>String</tt> which is a normalized form of the specified
@ -42,7 +42,7 @@ public interface PhoneNumberI18nService
* Indicates if the given string is possibly a phone number.
*
* @param possibleNumber the string to be verified
* @return
* @return true if the given string is a phone number, false otherwise
*/
public boolean isPhoneNumber(String possibleNumber);
}

@ -260,7 +260,12 @@ private void callStateChanged(CallChangeEvent callChangeEvent)
if (!call.equals(otherCall)
&& CallState.CALL_IN_PROGRESS
.equals(otherCall.getCallState()))
putOnHold(otherCall);
{
if((call.getCallGroup() != null ||
otherCall.getCallGroup() != null) &&
call.getCallGroup() != otherCall.getCallGroup())
putOnHold(otherCall);
}
}
}
}

@ -142,6 +142,22 @@ protected void basicTelephonyChanged(
*/
public Call createConfCall(String[] callees)
throws OperationFailedException
{
return createConfCall(callees, null);
}
/**
* Creates a conference call with the specified callees as call peers.
*
* @param callees the list of addresses that we should call
* @param group the <tt>CallGroup</tt> or null
* @return the newly created conference call containing all CallPeers
* @throws OperationFailedException if establishing the conference call
* fails
* @see OperationSetTelephonyConferencing#createConfCall(String[])
*/
public Call createConfCall(String[] callees, CallGroup group)
throws OperationFailedException
{
List<CalleeAddressT> calleeAddresses
= new ArrayList<CalleeAddressT>(callees.length);
@ -150,6 +166,11 @@ public Call createConfCall(String[] callees)
calleeAddresses.add(parseAddressString(callee));
MediaAwareCallT call = createOutgoingCall();
if(group.getCalls().size() > 0)
{
group.addCall(call);
call.setCallGroup(group);
}
call.setConferenceFocus(true);
@ -164,7 +185,19 @@ public Call createConfCall(String[] callees)
wasConferenceFocus = false;
call.setConferenceFocus(true);
}
inviteCalleeToCall(calleeAddress, call, wasConferenceFocus);
CallPeer p =
inviteCalleeToCall(calleeAddress, call, wasConferenceFocus);
// GTalk case
if(p.getCall() != call)
{
group.addCall(p.getCall());
}
if(call.getCallGroup() == null)
{
group.addCall(call);
}
}
return call;
}

@ -261,8 +261,23 @@ private void removeCallPeer(CallPeerChangeEvent evt)
callPeer.setCall(null);
}
if (getCallPeersVector().isEmpty())
if (getCallPeersVector().isEmpty() &&
getCrossProtocolCallPeersVector().isEmpty())
{
setCallState(CallState.CALL_ENDED, evt);
if(getCallGroup() != null)
{
for(Call c : getCallGroup().getCalls())
{
if(c == this)
continue;
((MediaAwareCall<?,?,?>)c).setCallState(
CallState.CALL_ENDED, evt);
}
}
}
}
/**
@ -1054,6 +1069,7 @@ public void callAdded(CallGroupEvent evt)
CallPeer p = peers.next();
getCrossProtocolCallPeersVector().add(p);
fireCallPeerEvent(p, CallPeerEvent.CALL_PEER_ADDED);
this.setConferenceFocus(true);
}
}

Loading…
Cancel
Save