Bug 1088672 - Part 7. Rewrite Loop's incoming call handling in the flux style. Remove the now redundant non-flux based code for incoming calls. r=mikedeboer
authorMark Banner <standard8@mozilla.com>
Thu, 12 Mar 2015 14:01:38 +0000
changeset 233233 9303663e42d3091197bb1283776f92d1f8857b02
parent 233232 ea81bbb5d288cf80edb126c6d75a45f4b19fa53c
child 233234 c154c877d4e473084f4d436f564e14594584739f
push id11728
push usermbanner@mozilla.com
push dateThu, 12 Mar 2015 14:02:24 +0000
treeherderfx-team@c154c877d4e4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer
bugs1088672
milestone39.0a1
Bug 1088672 - Part 7. Rewrite Loop's incoming call handling in the flux style. Remove the now redundant non-flux based code for incoming calls. r=mikedeboer
browser/components/loop/content/conversation.html
browser/components/loop/content/js/client.js
browser/components/loop/content/js/conversation.js
browser/components/loop/content/js/conversation.jsx
browser/components/loop/content/js/conversationAppStore.js
browser/components/loop/content/js/conversationViews.js
browser/components/loop/content/js/conversationViews.jsx
browser/components/loop/test/desktop-local/client_test.js
browser/components/loop/test/desktop-local/conversationAppStore_test.js
browser/components/loop/test/desktop-local/conversationViews_test.js
--- a/browser/components/loop/content/conversation.html
+++ b/browser/components/loop/content/conversation.html
@@ -21,17 +21,16 @@
     <script type="text/javascript" src="loop/js/otconfig.js"></script>
     <script type="text/javascript" src="loop/libs/sdk.js"></script>
     <script type="text/javascript" src="loop/shared/libs/react-0.12.2.js"></script>
     <script type="text/javascript" src="loop/shared/libs/jquery-2.1.0.js"></script>
     <script type="text/javascript" src="loop/shared/libs/lodash-2.4.1.js"></script>
     <script type="text/javascript" src="loop/shared/libs/backbone-1.1.2.js"></script>
 
     <script type="text/javascript" src="loop/shared/js/utils.js"></script>
-    <script type="text/javascript" src="loop/shared/js/models.js"></script>
     <script type="text/javascript" src="loop/shared/js/mixins.js"></script>
     <script type="text/javascript" src="loop/shared/js/feedbackApiClient.js"></script>
     <script type="text/javascript" src="loop/shared/js/actions.js"></script>
     <script type="text/javascript" src="loop/shared/js/validate.js"></script>
     <script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
     <script type="text/javascript" src="loop/shared/js/otSdkDriver.js"></script>
     <script type="text/javascript" src="loop/shared/js/store.js"></script>
     <script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
--- a/browser/components/loop/content/js/client.js
+++ b/browser/components/loop/content/js/client.js
@@ -71,47 +71,16 @@ loop.Client = (function($) {
      */
     _failureHandler: function(cb, error) {
       var message = "HTTP " + error.code + " " + error.error + "; " + error.message;
       console.error(message);
       cb(error);
     },
 
     /**
-     * Block call URL based on the token identifier
-     *
-     * @param {string} token Conversation identifier used to block the URL
-     * @param {mozLoop.LOOP_SESSION_TYPE} sessionType The type of session which
-     *                                                the url belongs to.
-     * @param {function} cb Callback function used for handling an error
-     *                      response. XXX The incoming call panel does not
-     *                      exist after the block button is clicked therefore
-     *                      it does not make sense to display an error.
-     **/
-    deleteCallUrl: function(token, sessionType, cb) {
-      function deleteRequestCallback(error, responseText) {
-        if (error) {
-          this._failureHandler(cb, error);
-          return;
-        }
-
-        try {
-          cb(null);
-        } catch (err) {
-          console.log("Error deleting call info", err);
-          cb(err);
-        }
-      }
-
-      this.mozLoop.hawkRequest(sessionType,
-                               "/call-url/" + token, "DELETE", null,
-                               deleteRequestCallback.bind(this));
-    },
-
-    /**
      * Sets up an outgoing call, getting the relevant data from the server.
      *
      * Callback parameters:
      * - err null on successful registration, non-null otherwise.
      * - result an object of the obtained data for starting the call, if successful
      *
      * @param {Array} calleeIds an array of emails and phone numbers.
      * @param {String} callType the type of call.
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -11,17 +11,16 @@ var loop = loop || {};
 loop.conversation = (function(mozL10n) {
   "use strict";
 
   var sharedViews = loop.shared.views;
   var sharedMixins = loop.shared.mixins;
   var sharedModels = loop.shared.models;
   var sharedActions = loop.shared.actions;
 
-  var IncomingConversationView = loop.conversationViews.IncomingConversationView;
   var CallControllerView = loop.conversationViews.CallControllerView;
   var CallIdentifierView = loop.conversationViews.CallIdentifierView;
   var DesktopRoomConversationView = loop.roomViews.DesktopRoomConversationView;
   var GenericFailureView = loop.conversationViews.GenericFailureView;
 
   /**
    * Master controller view for handling if incoming or outgoing calls are
    * in progress, and hence, which view to display.
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -11,17 +11,16 @@ var loop = loop || {};
 loop.conversation = (function(mozL10n) {
   "use strict";
 
   var sharedViews = loop.shared.views;
   var sharedMixins = loop.shared.mixins;
   var sharedModels = loop.shared.models;
   var sharedActions = loop.shared.actions;
 
-  var IncomingConversationView = loop.conversationViews.IncomingConversationView;
   var CallControllerView = loop.conversationViews.CallControllerView;
   var CallIdentifierView = loop.conversationViews.CallIdentifierView;
   var DesktopRoomConversationView = loop.roomViews.DesktopRoomConversationView;
   var GenericFailureView = loop.conversationViews.GenericFailureView;
 
   /**
    * Master controller view for handling if incoming or outgoing calls are
    * in progress, and hence, which view to display.
--- a/browser/components/loop/content/js/conversationAppStore.js
+++ b/browser/components/loop/content/js/conversationAppStore.js
@@ -64,22 +64,17 @@ loop.store.ConversationAppStore = (funct
       var windowData = this._mozLoop.getConversationWindowData(actionData.windowId);
 
       if (!windowData) {
         console.error("Failed to get the window data");
         this.setStoreState({windowType: "failed"});
         return;
       }
 
-      // XXX windowData is a hack for the IncomingConversationView until
-      // we rework it for the flux model in bug 1088672.
-      this.setStoreState({
-        windowType: windowData.type,
-        windowData: windowData
-      });
+      this.setStoreState({windowType: windowData.type});
 
       this._dispatcher.dispatch(new loop.shared.actions.SetupWindowData(_.extend({
         windowId: actionData.windowId}, windowData)));
     }
   }, Backbone.Events);
 
   return ConversationAppStore;
 
--- a/browser/components/loop/content/js/conversationViews.js
+++ b/browser/components/loop/content/js/conversationViews.js
@@ -309,19 +309,16 @@ loop.conversationViews = (function(mozL1
         )
         /* jshint ignore:end */
       );
     }
   });
 
   /**
    * Something went wrong view. Displayed when there's a big problem.
-   *
-   * XXX Based on CallFailedView, but built specially until we flux-ify the
-   * incoming call views (bug 1088672).
    */
   var GenericFailureView = React.createClass({displayName: "GenericFailureView",
     mixins: [sharedMixins.AudioMixin],
 
     propTypes: {
       cancelCall: React.PropTypes.func.isRequired
     },
 
@@ -343,337 +340,16 @@ loop.conversationViews = (function(mozL1
             )
           )
         )
       );
     }
   });
 
   /**
-   * This view manages the incoming conversation views - from
-   * call initiation through to the actual conversation and call end.
-   *
-   * At the moment, it does more than that, these parts need refactoring out.
-   */
-  var IncomingConversationView = React.createClass({displayName: "IncomingConversationView",
-    mixins: [sharedMixins.AudioMixin, sharedMixins.WindowCloseMixin],
-
-    propTypes: {
-      client: React.PropTypes.instanceOf(loop.Client).isRequired,
-      conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
-                         .isRequired,
-      sdk: React.PropTypes.object.isRequired,
-      isDesktop: React.PropTypes.bool,
-      conversationAppStore: React.PropTypes.instanceOf(
-        loop.store.ConversationAppStore).isRequired
-    },
-
-    getDefaultProps: function() {
-      return {
-        isDesktop: false
-      };
-    },
-
-    getInitialState: function() {
-      return {
-        callFailed: false, // XXX this should be removed when bug 1047410 lands.
-        callStatus: "start"
-      };
-    },
-
-    componentDidMount: function() {
-      this.props.conversation.on("accept", this.accept, this);
-      this.props.conversation.on("decline", this.decline, this);
-      this.props.conversation.on("declineAndBlock", this.declineAndBlock, this);
-      this.props.conversation.on("call:accepted", this.accepted, this);
-      this.props.conversation.on("change:publishedStream", this._checkConnected, this);
-      this.props.conversation.on("change:subscribedStream", this._checkConnected, this);
-      this.props.conversation.on("session:ended", this.endCall, this);
-      this.props.conversation.on("session:peer-hungup", this._onPeerHungup, this);
-      this.props.conversation.on("session:network-disconnected", this._onNetworkDisconnected, this);
-      this.props.conversation.on("session:connection-error", this._notifyError, this);
-
-      this.setupIncomingCall();
-    },
-
-    componentDidUnmount: function() {
-      this.props.conversation.off(null, null, this);
-    },
-
-    render: function() {
-      switch (this.state.callStatus) {
-        case "start": {
-          document.title = mozL10n.get("incoming_call_title2");
-
-          // XXX Don't render anything initially, though this should probably
-          // be some sort of pending view, whilst we connect the websocket.
-          return null;
-        }
-        case "incoming": {
-          document.title = mozL10n.get("incoming_call_title2");
-
-          return (
-            React.createElement(AcceptCallView, {
-              model: this.props.conversation, 
-              video: this.props.conversation.hasVideoStream("incoming")}
-            )
-          );
-        }
-        case "connected": {
-          document.title = this.props.conversation.getCallIdentifier();
-
-          var callType = this.props.conversation.get("selectedCallType");
-
-          return (
-            React.createElement(sharedViews.ConversationView, {
-              isDesktop: this.props.isDesktop, 
-              initiate: true, 
-              sdk: this.props.sdk, 
-              model: this.props.conversation, 
-              video: {enabled: callType !== "audio"}}
-            )
-          );
-        }
-        case "end": {
-          // XXX To be handled with the "failed" view state when bug 1047410 lands
-          if (this.state.callFailed) {
-            return React.createElement(GenericFailureView, {
-              cancelCall: this.closeWindow.bind(this)}
-            );
-          }
-
-          document.title = mozL10n.get("conversation_has_ended");
-
-          this.play("terminated");
-
-          return (
-            React.createElement(sharedViews.FeedbackView, {
-              onAfterFeedbackReceived: this.closeWindow.bind(this)}
-            )
-          );
-        }
-        case "close": {
-          this.closeWindow();
-          return (React.createElement("div", null));
-        }
-      }
-    },
-
-    /**
-     * Notify the user that the connection was not possible
-     * @param {{code: number, message: string}} error
-     */
-    _notifyError: function(error) {
-      // XXX Not the ideal response, but bug 1047410 will be replacing
-      // this by better "call failed" UI.
-      console.error(error);
-      this.setState({callFailed: true, callStatus: "end"});
-    },
-
-    /**
-     * Peer hung up. Notifies the user and ends the call.
-     *
-     * Event properties:
-     * - {String} connectionId: OT session id
-     */
-    _onPeerHungup: function() {
-      this.setState({callFailed: false, callStatus: "end"});
-    },
-
-    /**
-     * Network disconnected. Notifies the user and ends the call.
-     */
-    _onNetworkDisconnected: function() {
-      // XXX Not the ideal response, but bug 1047410 will be replacing
-      // this by better "call failed" UI.
-      this.setState({callFailed: true, callStatus: "end"});
-    },
-
-    /**
-     * Incoming call route.
-     */
-    setupIncomingCall: function() {
-      navigator.mozLoop.startAlerting();
-
-      // XXX This is a hack until we rework for the flux model in bug 1088672.
-      var callData = this.props.conversationAppStore.getStoreState().windowData;
-
-      this.props.conversation.setIncomingSessionData(callData);
-      this._setupWebSocket();
-    },
-
-    /**
-     * Starts the actual conversation
-     */
-    accepted: function() {
-      this.setState({callStatus: "connected"});
-    },
-
-    /**
-     * Moves the call to the end state
-     */
-    endCall: function() {
-      navigator.mozLoop.calls.clearCallInProgress(
-        this.props.conversation.get("windowId"));
-      this.setState({callStatus: "end"});
-    },
-
-    /**
-     * Used to set up the web socket connection and navigate to the
-     * call view if appropriate.
-     */
-    _setupWebSocket: function() {
-      this._websocket = new loop.CallConnectionWebSocket({
-        url: this.props.conversation.get("progressURL"),
-        websocketToken: this.props.conversation.get("websocketToken"),
-        callId: this.props.conversation.get("callId"),
-      });
-      this._websocket.promiseConnect().then(function(progressStatus) {
-        this.setState({
-          callStatus: progressStatus === "terminated" ? "close" : "incoming"
-        });
-      }.bind(this), function() {
-        this._handleSessionError();
-        return;
-      }.bind(this));
-
-      this._websocket.on("progress", this._handleWebSocketProgress, this);
-    },
-
-    /**
-     * Checks if the streams have been connected, and notifies the
-     * websocket that the media is now connected.
-     */
-    _checkConnected: function() {
-      // Check we've had both local and remote streams connected before
-      // sending the media up message.
-      if (this.props.conversation.streamsConnected()) {
-        this._websocket.mediaUp();
-      }
-    },
-
-    /**
-     * Used to receive websocket progress and to determine how to handle
-     * it if appropraite.
-     * If we add more cases here, then we should refactor this function.
-     *
-     * @param {Object} progressData The progress data from the websocket.
-     * @param {String} previousState The previous state from the websocket.
-     */
-    _handleWebSocketProgress: function(progressData, previousState) {
-      // We only care about the terminated state at the moment.
-      if (progressData.state !== "terminated")
-        return;
-
-      // XXX This would be nicer in the _abortIncomingCall function, but we need to stop
-      // it here for now due to server-side issues that are being fixed in bug 1088351.
-      // This is before the abort call to ensure that it happens before the window is
-      // closed.
-      navigator.mozLoop.stopAlerting();
-
-      // If we hit any of the termination reasons, and the user hasn't accepted
-      // then it seems reasonable to close the window/abort the incoming call.
-      //
-      // If the user has accepted the call, and something's happened, display
-      // the call failed view.
-      //
-      // https://wiki.mozilla.org/Loop/Architecture/MVP#Termination_Reasons
-      if (previousState === "init" || previousState === "alerting") {
-        this._abortIncomingCall();
-      } else {
-        this.setState({callFailed: true, callStatus: "end"});
-      }
-
-    },
-
-    /**
-     * Silently aborts an incoming call - stops the alerting, and
-     * closes the websocket.
-     */
-    _abortIncomingCall: function() {
-      this._websocket.close();
-      // Having a timeout here lets the logging for the websocket complete and be
-      // displayed on the console if both are on.
-      setTimeout(this.closeWindow, 0);
-    },
-
-    /**
-     * Accepts an incoming call.
-     */
-    accept: function() {
-      navigator.mozLoop.stopAlerting();
-      this._websocket.accept();
-      this.props.conversation.accepted();
-    },
-
-    /**
-     * Declines a call and handles closing of the window.
-     */
-    _declineCall: function() {
-      this._websocket.decline();
-      navigator.mozLoop.calls.clearCallInProgress(
-        this.props.conversation.get("windowId"));
-      this._websocket.close();
-      // Having a timeout here lets the logging for the websocket complete and be
-      // displayed on the console if both are on.
-      setTimeout(this.closeWindow, 0);
-    },
-
-    /**
-     * Declines an incoming call.
-     */
-    decline: function() {
-      navigator.mozLoop.stopAlerting();
-      this._declineCall();
-    },
-
-    /**
-     * Decline and block an incoming call
-     * @note:
-     * - loopToken is the callUrl identifier. It gets set in the panel
-     *   after a callUrl is received
-     */
-    declineAndBlock: function() {
-      navigator.mozLoop.stopAlerting();
-      var token = this.props.conversation.get("callToken");
-      var callerId = this.props.conversation.get("callerId");
-
-      // If this is a direct call, we'll need to block the caller directly.
-      if (callerId && EMAIL_OR_PHONE_RE.test(callerId)) {
-        navigator.mozLoop.calls.blockDirectCaller(callerId, function(err) {
-          // XXX The conversation window will be closed when this cb is triggered
-          // figure out if there is a better way to report the error to the user
-          // (bug 1103150).
-          console.log(err.fileName + ":" + err.lineNumber + ": " + err.message);
-        });
-      } else {
-        this.props.client.deleteCallUrl(token,
-          this.props.conversation.get("sessionType"),
-          function(error) {
-            // XXX The conversation window will be closed when this cb is triggered
-            // figure out if there is a better way to report the error to the user
-            // (bug 1048909).
-            console.log(error);
-          });
-      }
-
-      this._declineCall();
-    },
-
-    /**
-     * Handles a error starting the session
-     */
-    _handleSessionError: function() {
-      // XXX Not the ideal response, but bug 1047410 will be replacing
-      // this by better "call failed" UI.
-      console.error("Failed initiating the call session.");
-    },
-  });
-
-  /**
    * View for pending conversations. Displays a cancel button and appropriate
    * pending/ringing strings.
    */
   var PendingConversationView = React.createClass({displayName: "PendingConversationView",
     mixins: [sharedMixins.AudioMixin],
 
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
@@ -1078,14 +754,13 @@ loop.conversationViews = (function(mozL1
   return {
     PendingConversationView: PendingConversationView,
     CallIdentifierView: CallIdentifierView,
     ConversationDetailView: ConversationDetailView,
     CallFailedView: CallFailedView,
     _getContactDisplayName: _getContactDisplayName,
     GenericFailureView: GenericFailureView,
     AcceptCallView: AcceptCallView,
-    IncomingConversationView: IncomingConversationView,
     OngoingConversationView: OngoingConversationView,
     CallControllerView: CallControllerView
   };
 
 })(document.mozL10n || navigator.mozL10n);
--- a/browser/components/loop/content/js/conversationViews.jsx
+++ b/browser/components/loop/content/js/conversationViews.jsx
@@ -309,19 +309,16 @@ loop.conversationViews = (function(mozL1
         </div>
         /* jshint ignore:end */
       );
     }
   });
 
   /**
    * Something went wrong view. Displayed when there's a big problem.
-   *
-   * XXX Based on CallFailedView, but built specially until we flux-ify the
-   * incoming call views (bug 1088672).
    */
   var GenericFailureView = React.createClass({
     mixins: [sharedMixins.AudioMixin],
 
     propTypes: {
       cancelCall: React.PropTypes.func.isRequired
     },
 
@@ -343,337 +340,16 @@ loop.conversationViews = (function(mozL1
             </button>
           </div>
         </div>
       );
     }
   });
 
   /**
-   * This view manages the incoming conversation views - from
-   * call initiation through to the actual conversation and call end.
-   *
-   * At the moment, it does more than that, these parts need refactoring out.
-   */
-  var IncomingConversationView = React.createClass({
-    mixins: [sharedMixins.AudioMixin, sharedMixins.WindowCloseMixin],
-
-    propTypes: {
-      client: React.PropTypes.instanceOf(loop.Client).isRequired,
-      conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel)
-                         .isRequired,
-      sdk: React.PropTypes.object.isRequired,
-      isDesktop: React.PropTypes.bool,
-      conversationAppStore: React.PropTypes.instanceOf(
-        loop.store.ConversationAppStore).isRequired
-    },
-
-    getDefaultProps: function() {
-      return {
-        isDesktop: false
-      };
-    },
-
-    getInitialState: function() {
-      return {
-        callFailed: false, // XXX this should be removed when bug 1047410 lands.
-        callStatus: "start"
-      };
-    },
-
-    componentDidMount: function() {
-      this.props.conversation.on("accept", this.accept, this);
-      this.props.conversation.on("decline", this.decline, this);
-      this.props.conversation.on("declineAndBlock", this.declineAndBlock, this);
-      this.props.conversation.on("call:accepted", this.accepted, this);
-      this.props.conversation.on("change:publishedStream", this._checkConnected, this);
-      this.props.conversation.on("change:subscribedStream", this._checkConnected, this);
-      this.props.conversation.on("session:ended", this.endCall, this);
-      this.props.conversation.on("session:peer-hungup", this._onPeerHungup, this);
-      this.props.conversation.on("session:network-disconnected", this._onNetworkDisconnected, this);
-      this.props.conversation.on("session:connection-error", this._notifyError, this);
-
-      this.setupIncomingCall();
-    },
-
-    componentDidUnmount: function() {
-      this.props.conversation.off(null, null, this);
-    },
-
-    render: function() {
-      switch (this.state.callStatus) {
-        case "start": {
-          document.title = mozL10n.get("incoming_call_title2");
-
-          // XXX Don't render anything initially, though this should probably
-          // be some sort of pending view, whilst we connect the websocket.
-          return null;
-        }
-        case "incoming": {
-          document.title = mozL10n.get("incoming_call_title2");
-
-          return (
-            <AcceptCallView
-              model={this.props.conversation}
-              video={this.props.conversation.hasVideoStream("incoming")}
-            />
-          );
-        }
-        case "connected": {
-          document.title = this.props.conversation.getCallIdentifier();
-
-          var callType = this.props.conversation.get("selectedCallType");
-
-          return (
-            <sharedViews.ConversationView
-              isDesktop={this.props.isDesktop}
-              initiate={true}
-              sdk={this.props.sdk}
-              model={this.props.conversation}
-              video={{enabled: callType !== "audio"}}
-            />
-          );
-        }
-        case "end": {
-          // XXX To be handled with the "failed" view state when bug 1047410 lands
-          if (this.state.callFailed) {
-            return <GenericFailureView
-              cancelCall={this.closeWindow.bind(this)}
-            />;
-          }
-
-          document.title = mozL10n.get("conversation_has_ended");
-
-          this.play("terminated");
-
-          return (
-            <sharedViews.FeedbackView
-              onAfterFeedbackReceived={this.closeWindow.bind(this)}
-            />
-          );
-        }
-        case "close": {
-          this.closeWindow();
-          return (<div/>);
-        }
-      }
-    },
-
-    /**
-     * Notify the user that the connection was not possible
-     * @param {{code: number, message: string}} error
-     */
-    _notifyError: function(error) {
-      // XXX Not the ideal response, but bug 1047410 will be replacing
-      // this by better "call failed" UI.
-      console.error(error);
-      this.setState({callFailed: true, callStatus: "end"});
-    },
-
-    /**
-     * Peer hung up. Notifies the user and ends the call.
-     *
-     * Event properties:
-     * - {String} connectionId: OT session id
-     */
-    _onPeerHungup: function() {
-      this.setState({callFailed: false, callStatus: "end"});
-    },
-
-    /**
-     * Network disconnected. Notifies the user and ends the call.
-     */
-    _onNetworkDisconnected: function() {
-      // XXX Not the ideal response, but bug 1047410 will be replacing
-      // this by better "call failed" UI.
-      this.setState({callFailed: true, callStatus: "end"});
-    },
-
-    /**
-     * Incoming call route.
-     */
-    setupIncomingCall: function() {
-      navigator.mozLoop.startAlerting();
-
-      // XXX This is a hack until we rework for the flux model in bug 1088672.
-      var callData = this.props.conversationAppStore.getStoreState().windowData;
-
-      this.props.conversation.setIncomingSessionData(callData);
-      this._setupWebSocket();
-    },
-
-    /**
-     * Starts the actual conversation
-     */
-    accepted: function() {
-      this.setState({callStatus: "connected"});
-    },
-
-    /**
-     * Moves the call to the end state
-     */
-    endCall: function() {
-      navigator.mozLoop.calls.clearCallInProgress(
-        this.props.conversation.get("windowId"));
-      this.setState({callStatus: "end"});
-    },
-
-    /**
-     * Used to set up the web socket connection and navigate to the
-     * call view if appropriate.
-     */
-    _setupWebSocket: function() {
-      this._websocket = new loop.CallConnectionWebSocket({
-        url: this.props.conversation.get("progressURL"),
-        websocketToken: this.props.conversation.get("websocketToken"),
-        callId: this.props.conversation.get("callId"),
-      });
-      this._websocket.promiseConnect().then(function(progressStatus) {
-        this.setState({
-          callStatus: progressStatus === "terminated" ? "close" : "incoming"
-        });
-      }.bind(this), function() {
-        this._handleSessionError();
-        return;
-      }.bind(this));
-
-      this._websocket.on("progress", this._handleWebSocketProgress, this);
-    },
-
-    /**
-     * Checks if the streams have been connected, and notifies the
-     * websocket that the media is now connected.
-     */
-    _checkConnected: function() {
-      // Check we've had both local and remote streams connected before
-      // sending the media up message.
-      if (this.props.conversation.streamsConnected()) {
-        this._websocket.mediaUp();
-      }
-    },
-
-    /**
-     * Used to receive websocket progress and to determine how to handle
-     * it if appropraite.
-     * If we add more cases here, then we should refactor this function.
-     *
-     * @param {Object} progressData The progress data from the websocket.
-     * @param {String} previousState The previous state from the websocket.
-     */
-    _handleWebSocketProgress: function(progressData, previousState) {
-      // We only care about the terminated state at the moment.
-      if (progressData.state !== "terminated")
-        return;
-
-      // XXX This would be nicer in the _abortIncomingCall function, but we need to stop
-      // it here for now due to server-side issues that are being fixed in bug 1088351.
-      // This is before the abort call to ensure that it happens before the window is
-      // closed.
-      navigator.mozLoop.stopAlerting();
-
-      // If we hit any of the termination reasons, and the user hasn't accepted
-      // then it seems reasonable to close the window/abort the incoming call.
-      //
-      // If the user has accepted the call, and something's happened, display
-      // the call failed view.
-      //
-      // https://wiki.mozilla.org/Loop/Architecture/MVP#Termination_Reasons
-      if (previousState === "init" || previousState === "alerting") {
-        this._abortIncomingCall();
-      } else {
-        this.setState({callFailed: true, callStatus: "end"});
-      }
-
-    },
-
-    /**
-     * Silently aborts an incoming call - stops the alerting, and
-     * closes the websocket.
-     */
-    _abortIncomingCall: function() {
-      this._websocket.close();
-      // Having a timeout here lets the logging for the websocket complete and be
-      // displayed on the console if both are on.
-      setTimeout(this.closeWindow, 0);
-    },
-
-    /**
-     * Accepts an incoming call.
-     */
-    accept: function() {
-      navigator.mozLoop.stopAlerting();
-      this._websocket.accept();
-      this.props.conversation.accepted();
-    },
-
-    /**
-     * Declines a call and handles closing of the window.
-     */
-    _declineCall: function() {
-      this._websocket.decline();
-      navigator.mozLoop.calls.clearCallInProgress(
-        this.props.conversation.get("windowId"));
-      this._websocket.close();
-      // Having a timeout here lets the logging for the websocket complete and be
-      // displayed on the console if both are on.
-      setTimeout(this.closeWindow, 0);
-    },
-
-    /**
-     * Declines an incoming call.
-     */
-    decline: function() {
-      navigator.mozLoop.stopAlerting();
-      this._declineCall();
-    },
-
-    /**
-     * Decline and block an incoming call
-     * @note:
-     * - loopToken is the callUrl identifier. It gets set in the panel
-     *   after a callUrl is received
-     */
-    declineAndBlock: function() {
-      navigator.mozLoop.stopAlerting();
-      var token = this.props.conversation.get("callToken");
-      var callerId = this.props.conversation.get("callerId");
-
-      // If this is a direct call, we'll need to block the caller directly.
-      if (callerId && EMAIL_OR_PHONE_RE.test(callerId)) {
-        navigator.mozLoop.calls.blockDirectCaller(callerId, function(err) {
-          // XXX The conversation window will be closed when this cb is triggered
-          // figure out if there is a better way to report the error to the user
-          // (bug 1103150).
-          console.log(err.fileName + ":" + err.lineNumber + ": " + err.message);
-        });
-      } else {
-        this.props.client.deleteCallUrl(token,
-          this.props.conversation.get("sessionType"),
-          function(error) {
-            // XXX The conversation window will be closed when this cb is triggered
-            // figure out if there is a better way to report the error to the user
-            // (bug 1048909).
-            console.log(error);
-          });
-      }
-
-      this._declineCall();
-    },
-
-    /**
-     * Handles a error starting the session
-     */
-    _handleSessionError: function() {
-      // XXX Not the ideal response, but bug 1047410 will be replacing
-      // this by better "call failed" UI.
-      console.error("Failed initiating the call session.");
-    },
-  });
-
-  /**
    * View for pending conversations. Displays a cancel button and appropriate
    * pending/ringing strings.
    */
   var PendingConversationView = React.createClass({
     mixins: [sharedMixins.AudioMixin],
 
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
@@ -1078,14 +754,13 @@ loop.conversationViews = (function(mozL1
   return {
     PendingConversationView: PendingConversationView,
     CallIdentifierView: CallIdentifierView,
     ConversationDetailView: ConversationDetailView,
     CallFailedView: CallFailedView,
     _getContactDisplayName: _getContactDisplayName,
     GenericFailureView: GenericFailureView,
     AcceptCallView: AcceptCallView,
-    IncomingConversationView: IncomingConversationView,
     OngoingConversationView: OngoingConversationView,
     CallControllerView: CallControllerView
   };
 
 })(document.mozL10n || navigator.mozL10n);
--- a/browser/components/loop/test/desktop-local/client_test.js
+++ b/browser/components/loop/test/desktop-local/client_test.js
@@ -47,52 +47,16 @@ describe("loop.Client", function() {
     });
   });
 
   afterEach(function() {
     sandbox.restore();
   });
 
   describe("loop.Client", function() {
-    describe("#deleteCallUrl", function() {
-      it("should make a delete call to /call-url/{fakeToken}", function() {
-        client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.GUEST, callback);
-
-        sinon.assert.calledOnce(hawkRequestStub);
-        sinon.assert.calledWith(hawkRequestStub,
-                                mozLoop.LOOP_SESSION_TYPE.GUEST,
-                                "/call-url/" + fakeToken, "DELETE");
-      });
-
-      it("should call the callback with null when the request succeeds",
-         function() {
-
-           // Sets up the hawkRequest stub to trigger the callback with no error
-           // and the url.
-           hawkRequestStub.callsArgWith(4, null);
-
-           client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.FXA, callback);
-
-           sinon.assert.calledWithExactly(callback, null);
-         });
-
-      it("should send an error when the request fails", function() {
-        // Sets up the hawkRequest stub to trigger the callback with
-        // an error
-        hawkRequestStub.callsArgWith(4, fakeErrorRes);
-
-        client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.FXA, callback);
-
-        sinon.assert.calledOnce(callback);
-        sinon.assert.calledWithMatch(callback, sinon.match(function(err) {
-          return err.code == 400 && "invalid token" == err.message;
-        }));
-      });
-    });
-
     describe("#setupOutgoingCall", function() {
       var calleeIds, callType;
 
       beforeEach(function() {
         calleeIds = [
           "fakeemail", "fake phone"
         ];
         callType = "audio";
--- a/browser/components/loop/test/desktop-local/conversationAppStore_test.js
+++ b/browser/components/loop/test/desktop-local/conversationAppStore_test.js
@@ -58,18 +58,17 @@ describe("loop.store.ConversationAppStor
         mozLoop: fakeMozLoop
       });
     });
 
     it("should fetch the window type from the mozLoop API", function() {
       dispatcher.dispatch(new sharedActions.GetWindowData(fakeGetWindowData));
 
       expect(store.getStoreState()).eql({
-        windowType: "incoming",
-        windowData: fakeWindowData
+        windowType: "incoming"
       });
     });
 
     it("should dispatch a SetupWindowData action with the data from the mozLoop API",
       function() {
         sandbox.stub(dispatcher, "dispatch");
 
         store.getWindowData(new sharedActions.GetWindowData(fakeGetWindowData));
--- a/browser/components/loop/test/desktop-local/conversationViews_test.js
+++ b/browser/components/loop/test/desktop-local/conversationViews_test.js
@@ -713,538 +713,16 @@ describe("loop.conversationViews", funct
 
         store.setStoreState({callState: CALL_STATES.TERMINATED});
 
         TestUtils.findRenderedComponentWithType(view,
           loop.conversationViews.CallFailedView);
     });
   });
 
-  describe("IncomingConversationView", function() {
-    var conversationAppStore, conversation, client, icView, oldTitle,
-        feedbackStore;
-
-    function mountTestComponent() {
-      return TestUtils.renderIntoDocument(
-        React.createElement(loop.conversationViews.IncomingConversationView, {
-          client: client,
-          conversation: conversation,
-          sdk: {},
-          conversationAppStore: conversationAppStore
-        }));
-    }
-
-    beforeEach(function() {
-      oldTitle = document.title;
-      client = new loop.Client();
-      conversation = new loop.shared.models.ConversationModel({}, {
-        sdk: {}
-      });
-      conversation.set({windowId: 42});
-      var dispatcher = new loop.Dispatcher();
-      conversationAppStore = new loop.store.ConversationAppStore({
-        dispatcher: dispatcher,
-        mozLoop: navigator.mozLoop
-      });
-      feedbackStore = new loop.store.FeedbackStore(dispatcher, {
-        feedbackClient: {}
-      });
-      sandbox.stub(conversation, "setOutgoingSessionData");
-    });
-
-    afterEach(function() {
-      icView = undefined;
-      document.title = oldTitle;
-    });
-
-    describe("start", function() {
-      it("should set the title to incoming_call_title2", function() {
-        conversationAppStore.setStoreState({
-          windowData: {
-            progressURL:    "fake",
-            websocketToken: "fake",
-            callId: 42
-          }
-        });
-
-        icView = mountTestComponent();
-
-        expect(document.title).eql("incoming_call_title2");
-      });
-    });
-
-    describe("componentDidMount", function() {
-      var fakeSessionData, promise, resolveWebSocketConnect;
-      var rejectWebSocketConnect;
-
-      beforeEach(function() {
-        fakeSessionData  = {
-          sessionId:      "sessionId",
-          sessionToken:   "sessionToken",
-          apiKey:         "apiKey",
-          callType:       "callType",
-          callId:         "Hello",
-          progressURL:    "http://progress.example.com",
-          websocketToken: "7b"
-        };
-
-        conversationAppStore.setStoreState({
-          windowData: fakeSessionData
-        });
-
-        stubComponent(loop.conversationViews, "AcceptCallView");
-        stubComponent(sharedView, "ConversationView");
-      });
-
-      it("should start alerting", function() {
-        icView = mountTestComponent();
-
-        sinon.assert.calledOnce(navigator.mozLoop.startAlerting);
-      });
-
-      describe("Session Data setup", function() {
-        beforeEach(function() {
-          sandbox.stub(loop, "CallConnectionWebSocket").returns({
-            promiseConnect: function () {
-              promise = new Promise(function(resolve, reject) {
-                resolveWebSocketConnect = resolve;
-                rejectWebSocketConnect = reject;
-              });
-              return promise;
-            },
-            on: sinon.stub()
-          });
-        });
-
-        it("should store the session data", function() {
-          sandbox.stub(conversation, "setIncomingSessionData");
-
-          icView = mountTestComponent();
-
-          sinon.assert.calledOnce(conversation.setIncomingSessionData);
-          sinon.assert.calledWithExactly(conversation.setIncomingSessionData,
-                                         fakeSessionData);
-        });
-
-        it("should setup the websocket connection", function() {
-          icView = mountTestComponent();
-
-          sinon.assert.calledOnce(loop.CallConnectionWebSocket);
-          sinon.assert.calledWithExactly(loop.CallConnectionWebSocket, {
-            callId: "Hello",
-            url: "http://progress.example.com",
-            websocketToken: "7b"
-          });
-        });
-      });
-
-      describe("WebSocket Handling", function() {
-        beforeEach(function() {
-          promise = new Promise(function(resolve, reject) {
-            resolveWebSocketConnect = resolve;
-            rejectWebSocketConnect = reject;
-          });
-
-          sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect").returns(promise);
-        });
-
-        it("should set the state to incoming on success", function(done) {
-          icView = mountTestComponent();
-          resolveWebSocketConnect("incoming");
-
-          promise.then(function () {
-            expect(icView.state.callStatus).eql("incoming");
-            done();
-          });
-        });
-
-        it("should set the state to close on success if the progress " +
-          "state is terminated", function(done) {
-            icView = mountTestComponent();
-            resolveWebSocketConnect("terminated");
-
-            promise.then(function () {
-              expect(icView.state.callStatus).eql("close");
-              done();
-            });
-          });
-
-        // XXX implement me as part of bug 1047410
-        // see https://hg.mozilla.org/integration/fx-team/rev/5d2c69ebb321#l18.259
-        it.skip("should should switch view state to failed", function(done) {
-          icView = mountTestComponent();
-          rejectWebSocketConnect();
-
-          promise.then(function() {}, function() {
-            done();
-          });
-        });
-      });
-
-      describe("WebSocket Events", function() {
-        describe("Call cancelled or timed out before acceptance", function() {
-          beforeEach(function() {
-            // Mounting the test component automatically calls the required
-            // setup functions
-            icView = mountTestComponent();
-            promise = new Promise(function(resolve, reject) {
-              resolve();
-            });
-
-            sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect").returns(promise);
-            sandbox.stub(loop.CallConnectionWebSocket.prototype, "close");
-          });
-
-          describe("progress - terminated (previousState = alerting)", function() {
-            it("should stop alerting", function(done) {
-              promise.then(function() {
-                icView._websocket.trigger("progress", {
-                  state: "terminated",
-                  reason: WEBSOCKET_REASONS.TIMEOUT
-                }, "alerting");
-
-                sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
-                done();
-              });
-            });
-
-            it("should close the websocket", function(done) {
-              promise.then(function() {
-                icView._websocket.trigger("progress", {
-                  state: "terminated",
-                  reason: WEBSOCKET_REASONS.CLOSED
-                }, "alerting");
-
-                sinon.assert.calledOnce(icView._websocket.close);
-                done();
-              });
-            });
-
-            it("should close the window", function(done) {
-              promise.then(function() {
-                icView._websocket.trigger("progress", {
-                  state: "terminated",
-                  reason: WEBSOCKET_REASONS.ANSWERED_ELSEWHERE
-                }, "alerting");
-
-                sandbox.clock.tick(1);
-
-                sinon.assert.calledOnce(fakeWindow.close);
-                done();
-              });
-            });
-          });
-
-
-          describe("progress - terminated (previousState not init" +
-                   " nor alerting)",
-            function() {
-              it("should set the state to end", function(done) {
-                promise.then(function() {
-                  icView._websocket.trigger("progress", {
-                    state: "terminated",
-                    reason: WEBSOCKET_REASONS.MEDIA_FAIL
-                  }, "connecting");
-
-                  expect(icView.state.callStatus).eql("end");
-                  done();
-                });
-              });
-
-              it("should stop alerting", function(done) {
-                promise.then(function() {
-                  icView._websocket.trigger("progress", {
-                    state: "terminated",
-                    reason: WEBSOCKET_REASONS.MEDIA_FAIL
-                  }, "connecting");
-
-                  sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
-                  done();
-                });
-              });
-            });
-        });
-      });
-
-      describe("#accept", function() {
-        beforeEach(function() {
-          icView = mountTestComponent();
-          conversation.setIncomingSessionData({
-            sessionId:      "sessionId",
-            sessionToken:   "sessionToken",
-            apiKey:         "apiKey",
-            callType:       "callType",
-            callId:         "Hello",
-            progressURL:    "http://progress.example.com",
-            websocketToken: 123
-          });
-
-          sandbox.stub(icView._websocket, "accept");
-          sandbox.stub(icView.props.conversation, "accepted");
-        });
-
-        it("should initiate the conversation", function() {
-          icView.accept();
-
-          sinon.assert.calledOnce(icView.props.conversation.accepted);
-        });
-
-        it("should notify the websocket of the user acceptance", function() {
-          icView.accept();
-
-          sinon.assert.calledOnce(icView._websocket.accept);
-        });
-
-        it("should stop alerting", function() {
-          icView.accept();
-
-          sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
-        });
-      });
-
-      describe("#decline", function() {
-        beforeEach(function() {
-          icView = mountTestComponent();
-
-          icView._websocket = {
-            decline: sinon.stub(),
-            close: sinon.stub()
-          };
-          conversation.set({
-            windowId: "8699"
-          });
-          conversation.setIncomingSessionData({
-            websocketToken: 123
-          });
-        });
-
-        it("should close the window", function() {
-          icView.decline();
-
-          sandbox.clock.tick(1);
-
-          sinon.assert.calledOnce(fakeWindow.close);
-        });
-
-        it("should stop alerting", function() {
-          icView.decline();
-
-          sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
-        });
-
-        it("should release callData", function() {
-          icView.decline();
-
-          sinon.assert.calledOnce(navigator.mozLoop.calls.clearCallInProgress);
-          sinon.assert.calledWithExactly(
-            navigator.mozLoop.calls.clearCallInProgress, "8699");
-        });
-      });
-
-      describe("#blocked", function() {
-        var mozLoop, deleteCallUrlStub;
-
-        beforeEach(function() {
-          icView = mountTestComponent();
-
-          icView._websocket = {
-            decline: sinon.spy(),
-            close: sinon.stub()
-          };
-
-          mozLoop = {
-            LOOP_SESSION_TYPE: {
-              GUEST: 1,
-              FXA: 2
-            }
-          };
-
-          deleteCallUrlStub = sandbox.stub(loop.Client.prototype,
-                                           "deleteCallUrl");
-        });
-
-        it("should call mozLoop.stopAlerting", function() {
-          icView.declineAndBlock();
-
-          sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
-        });
-
-        it("should call delete call", function() {
-          sandbox.stub(conversation, "get").withArgs("callToken")
-                                           .returns("fakeToken")
-                                           .withArgs("sessionType")
-                                           .returns(mozLoop.LOOP_SESSION_TYPE.FXA);
-
-          icView.declineAndBlock();
-
-          sinon.assert.calledOnce(deleteCallUrlStub);
-          sinon.assert.calledWithExactly(deleteCallUrlStub,
-            "fakeToken", mozLoop.LOOP_SESSION_TYPE.FXA, sinon.match.func);
-        });
-
-        it("should get callToken from conversation model", function() {
-          sandbox.stub(conversation, "get");
-          icView.declineAndBlock();
-
-          sinon.assert.called(conversation.get);
-          sinon.assert.calledWithExactly(conversation.get, "callToken");
-          sinon.assert.calledWithExactly(conversation.get, "windowId");
-        });
-
-        it("should trigger error handling in case of error", function() {
-          // XXX just logging to console for now
-          var log = sandbox.stub(console, "log");
-          var fakeError = {
-            error: true
-          };
-          deleteCallUrlStub.callsArgWith(2, fakeError);
-          icView.declineAndBlock();
-
-          sinon.assert.calledOnce(log);
-          sinon.assert.calledWithExactly(log, fakeError);
-        });
-
-        it("should close the window", function() {
-          icView.declineAndBlock();
-
-          sandbox.clock.tick(1);
-
-          sinon.assert.calledOnce(fakeWindow.close);
-        });
-      });
-    });
-
-    describe("Events", function() {
-      var fakeSessionData;
-
-      beforeEach(function() {
-
-        fakeSessionData = {
-          sessionId:    "sessionId",
-          sessionToken: "sessionToken",
-          apiKey:       "apiKey"
-        };
-
-        conversationAppStore.setStoreState({
-          windowData: fakeSessionData
-        });
-
-        sandbox.stub(conversation, "setIncomingSessionData");
-        sandbox.stub(loop, "CallConnectionWebSocket").returns({
-          promiseConnect: function() {
-            return new Promise(function() {});
-          },
-          on: sandbox.spy()
-        });
-
-        icView = mountTestComponent();
-
-        conversation.set("loopToken", "fakeToken");
-        stubComponent(sharedView, "ConversationView");
-      });
-
-      describe("call:accepted", function() {
-        it("should display the ConversationView",
-          function() {
-            conversation.accepted();
-
-            TestUtils.findRenderedComponentWithType(icView,
-              sharedView.ConversationView);
-          });
-
-        it("should set the title to the call identifier", function() {
-          sandbox.stub(conversation, "getCallIdentifier").returns("fakeId");
-
-          conversation.accepted();
-
-          expect(document.title).eql("fakeId");
-        });
-      });
-
-      describe("session:ended", function() {
-        it("should display the feedback view when the call session ends",
-          function() {
-            conversation.trigger("session:ended");
-
-            TestUtils.findRenderedComponentWithType(icView,
-              sharedView.FeedbackView);
-          });
-      });
-
-      describe("session:peer-hungup", function() {
-        it("should display the feedback view when the peer hangs up",
-          function() {
-            conversation.trigger("session:peer-hungup");
-
-              TestUtils.findRenderedComponentWithType(icView,
-                sharedView.FeedbackView);
-          });
-      });
-
-      describe("session:network-disconnected", function() {
-        it("should navigate to call failed when network disconnects",
-          function() {
-            conversation.trigger("session:network-disconnected");
-
-            TestUtils.findRenderedComponentWithType(icView,
-              loop.conversationViews.GenericFailureView);
-          });
-
-        it("should update the conversation window toolbar title",
-          function() {
-            conversation.trigger("session:network-disconnected");
-
-            expect(document.title).eql("generic_failure_title");
-          });
-      });
-
-      describe("Published and Subscribed Streams", function() {
-        beforeEach(function() {
-          icView._websocket = {
-            mediaUp: sinon.spy()
-          };
-        });
-
-        describe("publishStream", function() {
-          it("should not notify the websocket if only one stream is up",
-            function() {
-              conversation.set("publishedStream", true);
-
-              sinon.assert.notCalled(icView._websocket.mediaUp);
-            });
-
-          it("should notify the websocket that media is up if both streams" +
-             "are connected", function() {
-              conversation.set("subscribedStream", true);
-              conversation.set("publishedStream", true);
-
-              sinon.assert.calledOnce(icView._websocket.mediaUp);
-            });
-        });
-
-        describe("subscribedStream", function() {
-          it("should not notify the websocket if only one stream is up",
-            function() {
-              conversation.set("subscribedStream", true);
-
-              sinon.assert.notCalled(icView._websocket.mediaUp);
-            });
-
-          it("should notify the websocket that media is up if both streams" +
-             "are connected", function() {
-              conversation.set("publishedStream", true);
-              conversation.set("subscribedStream", true);
-
-              sinon.assert.calledOnce(icView._websocket.mediaUp);
-            });
-        });
-      });
-    });
-  });
-
   describe("AcceptCallView", function() {
     var view;
 
     function mountTestComponent(extraProps) {
       var props = _.extend({dispatcher: dispatcher, mozLoop: fakeMozLoop}, extraProps);
       return TestUtils.renderIntoDocument(
         React.createElement(loop.conversationViews.AcceptCallView, props));
     }