예제 #1
0
  /**
   * Creates a <tt>CallPeerPanel</tt> for the given call peer.
   *
   * @param callRenderer the renderer of the call
   * @param callPeer the <tt>CallPeer</tt> represented in this panel
   * @param uiVideoHandler the facility which is to aid the new instance in the dealing with the
   *     video-related information
   */
  public OneToOneCallPeerPanel(
      SwingCallRenderer callRenderer, CallPeer callPeer, UIVideoHandler2 uiVideoHandler) {
    this.callRenderer = callRenderer;
    this.callPeer = callPeer;
    // we need to obtain call as soon as possible
    // cause if it fails too quickly we may fail to show it
    this.call = callPeer.getCall();
    this.uiVideoHandler = uiVideoHandler;

    peerName = CallManager.getPeerDisplayName(callPeer);
    securityPanel = SecurityPanel.create(this, callPeer, null);

    photoLabel = new JLabel(getPhotoLabelIcon());
    center = createCenter();
    statusBar = createStatusBar();

    setPeerImage(CallManager.getPeerImage(callPeer));

    /* Lay out the main Components of the UI. */
    setLayout(new GridBagLayout());

    GridBagConstraints cnstrnts = new GridBagConstraints();

    if (center != null) {
      cnstrnts.fill = GridBagConstraints.BOTH;
      cnstrnts.gridx = 0;
      cnstrnts.gridy = 1;
      cnstrnts.weightx = 1;
      cnstrnts.weighty = 1;
      add(center, cnstrnts);
    }
    if (statusBar != null) {
      cnstrnts.fill = GridBagConstraints.NONE;
      cnstrnts.gridx = 0;
      cnstrnts.gridy = 3;
      cnstrnts.weightx = 0;
      cnstrnts.weighty = 0;
      cnstrnts.insets = new Insets(5, 0, 0, 0);
      add(statusBar, cnstrnts);
    }

    createSoundLevelIndicators();
    initSecuritySettings();

    /*
     * Add the listeners which will be notified about changes in the model
     * and which will update this view.
     */
    callPeerAdapter = new CallPeerAdapter(callPeer, this);
    uiVideoHandler.addObserver(uiVideoHandlerObserver);

    /*
     * This view adapts to whether it is displayed in full-screen or
     * windowed mode.
     */
    if (callRenderer instanceof Component) {
      ((Component) callRenderer).addPropertyChangeListener(CallContainer.PROP_FULL_SCREEN, this);
    }

    OperationSetDesktopSharingClient desktopSharingClient =
        callPeer.getProtocolProvider().getOperationSet(OperationSetDesktopSharingClient.class);
    if (desktopSharingClient != null) {
      desktopSharingMouseAndKeyboardListener =
          new DesktopSharingMouseAndKeyboardListener(callPeer, desktopSharingClient);
    } else desktopSharingMouseAndKeyboardListener = null;

    updateViewFromModel();
  }
예제 #2
0
  /**
   * Indicates that the security is turned on.
   *
   * <p>Sets the secured status icon to the status panel and initializes/updates the corresponding
   * security details.
   *
   * @param evt Details about the event that caused this message.
   */
  public void securityOn(final CallPeerSecurityOnEvent evt) {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              securityOn(evt);
            }
          });
      return;
    }

    // If the securityOn is called without a specific event, we'll just set
    // the security label status to on.
    if (evt == null) {
      securityStatusLabel.setSecurityOn();
      return;
    }

    SrtpControl srtpControl = evt.getSecurityController();

    if (!srtpControl.requiresSecureSignalingTransport()
        || callPeer.getProtocolProvider().isSignalingTransportSecure()) {
      if (srtpControl instanceof ZrtpControl) {
        securityStatusLabel.setText("zrtp");

        if (!((ZrtpControl) srtpControl).isSecurityVerified())
          securityStatusLabel.setSecurityPending();
        else securityStatusLabel.setSecurityOn();
      } else securityStatusLabel.setSecurityOn();
    }

    // if we have some other panel, using other control
    if (!srtpControl.getClass().isInstance(securityPanel.getSecurityControl())
        || (securityPanel instanceof ParanoiaTimerSecurityPanel)) {
      setSecurityPanelVisible(false);

      securityPanel = SecurityPanel.create(this, callPeer, srtpControl);

      if (srtpControl instanceof ZrtpControl)
        ((ZrtpSecurityPanel) securityPanel).setSecurityStatusLabel(securityStatusLabel);
    }

    securityPanel.securityOn(evt);

    boolean isSecurityLowPriority =
        Boolean.parseBoolean(
            GuiActivator.getResources()
                .getSettingsString("impl.gui.I_DONT_CARE_THAT_MUCH_ABOUT_SECURITY"));

    // Display ZRTP panel in case SAS was not verified or a AOR mismtach
    // was detected during creation of ZrtpSecurityPanel.
    // Don't show panel if user does not care about security at all.
    if (srtpControl instanceof ZrtpControl
        && !isSecurityLowPriority
        && (!((ZrtpControl) srtpControl).isSecurityVerified()
            || ((ZrtpSecurityPanel) securityPanel).isZidAorMismatch())) {
      setSecurityPanelVisible(true);
    }

    this.revalidate();
  }
예제 #3
0
  /**
   * Updates this view i.e. <tt>OneToOneCallPeerPanel</tt> so that it depicts the current state of
   * its model i.e. <tt>callPeer</tt>. The update is performed in the AWT event dispatching thread.
   */
  private void updateViewFromModelInEventDispatchThread() {
    /*
     * We receive events/notifications from various threads and we respond
     * to them in the AWT event dispatching thread. It is possible to first
     * schedule an event to be brought to the AWT event dispatching thread,
     * then to have #dispose() invoked on this instance and, finally, to
     * receive the scheduled event in the AWT event dispatching thread. In
     * such a case, this disposed instance should not respond to the event
     * because it may, for example, steal a visual Components depicting
     * video (which cannot belong to more than one parent at a time) from
     * another non-disposed OneToOneCallPeerPanel.
     */
    if (disposed) return;

    /*
     * Update the display of visual <tt>Component</tt>s depicting video
     * streaming between the local peer/user and the remote peer(s).
     */

    OperationSetVideoTelephony videoTelephony =
        callPeer.getProtocolProvider().getOperationSet(OperationSetVideoTelephony.class);
    Component remoteVideo = null;
    Component localVideo = null;

    if (videoTelephony != null) {
      List<Component> remoteVideos = videoTelephony.getVisualComponents(callPeer);

      if ((remoteVideos != null) && !remoteVideos.isEmpty()) {
        /*
         * TODO OneToOneCallPeerPanel displays a one-to-one conversation
         * between the local peer/user and a specific remote peer. If
         * the remote peer is the focus of a telephony conference of its
         * own, it may be sending multiple videos to the local peer.
         * Switching to a user interface which displays multiple videos
         * is the responsibility of whoever decided that this
         * OneToOneCallPeerPanel is to be used to depict the current
         * state of the CallConference associated with the CallPeer
         * depicted by this instance. If that switching decides that
         * this instance is to continue being the user interface, then
         * we should probably pick up the remote video which is
         * generated by the remote peer and not one of its
         * ConferenceMembers.
         */
        remoteVideo = remoteVideos.get(0);
      }

      if (uiVideoHandler.isLocalVideoVisible()) {
        try {
          localVideo = videoTelephony.getLocalVisualComponent(callPeer);
        } catch (OperationFailedException ofe) {
          /*
           * Well, we cannot do much about the exception. We'll just
           * not display the local video.
           */
          logger.warn("Failed to retrieve local video to be displayed.", ofe);
        }
      }

      /*
       * Determine whether there is actually a change in the local and
       * remote videos which requires an update.
       */
      boolean localVideoChanged =
          ((localVideo != this.localVideo)
              || ((localVideo != null) && !UIVideoHandler2.isAncestor(center, localVideo)));
      boolean remoteVideoChanged =
          ((remoteVideo != this.remoteVideo)
              || ((remoteVideo != null) && !UIVideoHandler2.isAncestor(center, remoteVideo)));

      // If the remote video has changed, maybe the CallPanel can display
      // the LO/SD/HD button.
      if (remoteVideoChanged) {
        // Updates video component which may listen the mouse and key
        // events.
        if (desktopSharingMouseAndKeyboardListener != null) {
          desktopSharingMouseAndKeyboardListener.setVideoComponent(remoteVideo);
        }

        CallPanel callPanel = callRenderer.getCallContainer();
        // The remote video has been added, then tries to display the
        // LO/SD/HD button.
        if (remoteVideo != null) {
          callPanel.addRemoteVideoSpecificComponents(callPeer);
        }
        // The remote video has been removed, then hide the LO/SD/HD
        // button if it is currently displayed.
        else {
          callPanel.removeRemoteVideoSpecificComponents();
        }
      }

      if (localVideoChanged || remoteVideoChanged) {
        /*
         * VideoContainer and JAWTRenderer cannot handle random
         * additions of Components. Removing the localVideo when the
         * user has requests its hiding though, should work without
         * removing all Components from the VideoCotainer and adding
         * them again.
         */
        if (localVideoChanged && !remoteVideoChanged && (localVideo == null)) {
          if (this.localVideo != null) {
            center.remove(this.localVideo);
            this.localVideo = null;

            if (closeLocalVisualComponentButton != null)
              center.remove(closeLocalVisualComponentButton);
          }
        } else {
          center.removeAll();
          this.localVideo = null;
          this.remoteVideo = null;

          /*
           * AWT does not make a guarantee about the Z order even
           * within an operating system i.e. the order of adding the
           * Components to their Container does not mean that they
           * will be determinedly painted in that or reverse order.
           * Anyway, there appears to be an expectation among the
           * developers less acquainted with AWT that AWT paints the
           * Components of a Container in an order that is the reverse
           * of the order of their adding. In order to satisfy that
           * expectation and thus give at least some idea to the
           * developers reading the code bellow, do add the Components
           * according to that expectation.
           */

          if (localVideo != null) {
            if (closeLocalVisualComponentButton == null) {
              closeLocalVisualComponentButton = new CloseLocalVisualComponentButton(uiVideoHandler);
            }
            center.add(closeLocalVisualComponentButton, VideoLayout.CLOSE_LOCAL_BUTTON, -1);

            center.add(localVideo, VideoLayout.LOCAL, -1);
            this.localVideo = localVideo;
          }

          if (remoteVideo != null) {
            center.add(remoteVideo, VideoLayout.CENTER_REMOTE, -1);
            this.remoteVideo = remoteVideo;
          }
        }
      }
    }
  }