private void processCallStateChange(ImsCall imsCall, ImsPhoneCall.State state, int cause) {
    if (DBG) log("processCallStateChange " + imsCall + " state=" + state + " cause=" + cause);

    if (imsCall == null) return;

    boolean changed = false;
    ImsPhoneConnection conn = findConnection(imsCall);

    if (conn == null) {
      // TODO : what should be done?
      return;
    }

    changed = conn.update(imsCall, state);

    if (state == ImsPhoneCall.State.DISCONNECTED) {
      changed = conn.onDisconnect(cause) || changed;
      // detach the disconnected connections
      conn.getCall().detach(conn);
      removeConnection(conn);
    }

    if (changed) {
      if (conn.getCall() == mHandoverCall) return;
      updatePhoneState();
      mPhone.notifyPreciseCallStateChanged();
    }
  }
  /*package*/ void hangup(ImsPhoneConnection conn) throws CallStateException {
    if (DBG) log("hangup connection");

    if (conn.getOwner() != this) {
      throw new CallStateException(
          "ImsPhoneConnection " + conn + "does not belong to ImsPhoneCallTracker " + this);
    }

    hangup(conn.getCall());
  }