/* * 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.impl.gui.main.call; import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.plugin.desktoputil.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.skin.*; import org.jitsi.util.*; /** * The dialog created when an incoming call is received. * * @author Yana Stamcheva * @author Adam Netocny */ public class ReceivedCallDialog extends PreCallDialog implements ActionListener, CallListener, Skinnable { /** * The incoming call to render. */ private final Call incomingCall; /** * The list of resolvers. */ private List<DisplayNameAndImageChangeListener> detailsResolvers = new ArrayList<DisplayNameAndImageChangeListener>(); /** * Creates a <tt>ReceivedCallDialog</tt> by specifying the associated call. * * @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) * @param desktopStreaming whether the incoming call is desktop streaming */ public ReceivedCallDialog( Call call, boolean video, boolean existingCall, boolean desktopStreaming) { super(GuiActivator.getResources() .getSettingsString("service.gui.APPLICATION_NAME") + " " + (desktopStreaming ? GuiActivator.getResources() .getI18NString("service.gui.INCOMING_SCREEN_SHARE_STATUS") .toLowerCase() : GuiActivator.getResources() .getI18NString("service.gui.INCOMING_CALL_STATUS") .toLowerCase()) , video, existingCall); this.incomingCall = call; OperationSetBasicTelephony<?> basicTelephony = call.getProtocolProvider().getOperationSet( OperationSetBasicTelephony.class); basicTelephony.addCallListener(this); initCallLabel(getCallLabels()); } /** * Initializes the label of the received call. * * @param callLabel The label to initialize. */ private void initCallLabel(final JLabel callLabel[]) { Iterator<? extends CallPeer> peersIter = incomingCall.getCallPeers(); String textAddress = ""; String textAccount = ""; ImageIcon imageIcon = ImageUtils.scaleIconWithinBounds(ImageLoader .getImage(ImageLoader.DEFAULT_USER_PHOTO), 40, 45); // we use a table to store peers and so far resolved names // in order to be able to reconstruct the text to display if we // receive the display name later Hashtable<CallPeer, String> peerNamesTable = new Hashtable<CallPeer, String>(); while (peersIter.hasNext()) { final CallPeer peer = peersIter.next(); String peerAddress = getPeerDisplayAddress(peer); textAccount = peer.getProtocolProvider().getAccountID() .getDisplayName(); DisplayNameAndImageChangeListener listener = new DisplayNameAndImageChangeListener(peer, peerNamesTable); detailsResolvers.add(listener); String displayName = CallManager.getPeerDisplayName(peer, listener); if(displayName != null) peerNamesTable.put(peer, displayName); if(!StringUtils.isNullOrEmpty(peerAddress)) textAddress = callLabel[2].getText() + trimPeerAddressToUsername(peerAddress); // More peers. if (peersIter.hasNext()) { textAddress += ", "; } else { byte[] image = CallManager.getPeerImage(peer); if (image != null && image.length > 0) imageIcon = ImageUtils.getScaledRoundedIcon(image, 50, 50); } } // will update callLabel[1] with the already found names updateTextDisplayName(peerNamesTable); callLabel[0].setIcon(imageIcon); callLabel[2].setText(textAddress); callLabel[2].setForeground(Color.GRAY); if(textAccount != null) { callLabel[3].setText( GuiActivator.getResources().getI18NString("service.gui.TO") + " " + textAccount); } } /** * Uses a table mapping peer to name to update call label display name. * @param peerNamesTable the peer to name mapping */ private void updateTextDisplayName( final Hashtable<CallPeer, String> peerNamesTable) { if(!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateTextDisplayName(peerNamesTable); } }); return; } boolean hasMorePeers = false; String textDisplayName = ""; Iterator<? extends CallPeer> peersIter = incomingCall.getCallPeers(); JLabel label = getCallLabels()[1]; while (peersIter.hasNext()) { final CallPeer peer = peersIter.next(); // More peers. if (peersIter.hasNext()) { textDisplayName = label.getText() + peerNamesTable.get(peer) + ", "; hasMorePeers = true; } // Only one peer. else { textDisplayName = GuiActivator.getResources() .getI18NString("service.gui.IS_CALLING", new String[]{ peerNamesTable.get(peer) }); } } if (hasMorePeers) textDisplayName = GuiActivator.getResources() .getI18NString("service.gui.ARE_CALLING", new String[]{textDisplayName}); label.setText(textDisplayName); } /** * {@inheritDoc} * * When the <tt>Call</tt> depicted by this dialog is (remotely) ended, * close/dispose of this dialog. * * @param event a <tt>CallEvent</tt> which specifies the <tt>Call</tt> that * has ended */ public void callEnded(CallEvent event) { if (event.getSourceCall().equals(incomingCall)) dispose(); } @Override public void dispose() { // no more queries needed, if they are still running for(DisplayNameAndImageChangeListener listener : detailsResolvers) { listener.setInterested(false); } try { OperationSetBasicTelephony<?> basicTelephony = incomingCall.getProtocolProvider().getOperationSet( OperationSetBasicTelephony.class); basicTelephony.removeCallListener(this); } finally { super.dispose(); } } /** * Indicates that an incoming call has been received. */ public void incomingCallReceived(CallEvent event) {} /** * Indicates that an outgoing call has been created. */ public void outgoingCallCreated(CallEvent event) {} /** * Answers the call when the call button has been pressed. */ @Override 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. */ @Override public void videoCallButtonPressed() { CallManager.answerVideoCall(incomingCall); } /** * Hangups the call when the call button has been pressed. */ @Override public void hangupButtonPressed() { CallManager.hangupCall(incomingCall); } /** * A informative text to show for the peer. If display name and * address are the same return null. * @param peer the peer. * @return the text contain address. */ private String getPeerDisplayAddress(CallPeer peer) { String peerAddress = peer.getAddress(); if(StringUtils.isNullOrEmpty(peerAddress, true)) return null; else { return peerAddress.equalsIgnoreCase(peer.getDisplayName()) ? null : peerAddress; } } /** * Removes the domain/server part from the address only if it is enabled. * @param peerAddress peer address to change. * @return username part of the address. */ private String trimPeerAddressToUsername(String peerAddress) { if(ConfigurationUtils.isHideDomainInReceivedCallDialogEnabled()) { if(peerAddress != null && !peerAddress.startsWith("@")) { return peerAddress.split("@")[0]; } } return peerAddress; } /** * Listens for display name update and image update, some searches for * display name are slow, so we add a listener to update them when * result comes in. */ private class DisplayNameAndImageChangeListener implements CallManager.DetailsResolveListener { /** * The call peer we are interested in. */ private CallPeer peer; /** * The table with all discovered peer names. */ private Hashtable<CallPeer, String> peerNamesTable; /** * By default we are interested in events. */ private boolean interested = true; /** * Constructs. * @param peer * @param peerNamesTable */ private DisplayNameAndImageChangeListener( CallPeer peer, Hashtable<CallPeer, String> peerNamesTable) { this.peer = peer; this.peerNamesTable = peerNamesTable; } @Override public void displayNameUpdated(String displayName) { if(displayName != null) { peerNamesTable.put(peer, displayName); updateTextDisplayName(peerNamesTable); } } @Override public void imageUpdated(byte[] image) { if(image != null) ImageUtils.setScaledLabelImage( getCallLabels()[0], image, 50, 50); } /** * Are we interested. * @return */ @Override public boolean isInterested() { return interested; } /** * Changes the interested value. * @param value */ public void setInterested(boolean value) { this.interested = value; } } }