/**
   * Called when a call becomes disconnected. Called everytime an existing call changes from being
   * connected (incoming/outgoing/active) to disconnected.
   */
  @Override
  public void onDisconnect(Call call) {
    hideDialpadForDisconnect();
    maybeShowErrorDialogOnDisconnect(call);

    // We need to do the run the same code as onCallListChange.
    onCallListChange(CallList.getInstance());

    if (isActivityStarted()) {
      mInCallActivity.dismissKeyguard(false);
    }
  }
  /**
   * Called when the UI begins or ends. Starts the callstate callbacks if the UI just began.
   * Attempts to tear down everything if the UI just ended. See #tearDown for more insight on the
   * tear-down process.
   */
  public void setActivity(InCallActivity inCallActivity) {
    boolean updateListeners = false;
    boolean doAttemptCleanup = false;

    if (inCallActivity != null) {
      if (mInCallActivity == null) {
        updateListeners = true;
        Log.i(this, "UI Initialized");
      } else if (mInCallActivity != inCallActivity) {
        Log.wtf(this, "Setting a second activity before destroying the first.");
      } else {
        // since setActivity is called onStart(), it can be called multiple times.
        // This is fine and ignorable, but we do not want to update the world every time
        // this happens (like going to/from background) so we do not set updateListeners.
      }

      mInCallActivity = inCallActivity;

      // By the time the UI finally comes up, the call may already be disconnected.
      // If that's the case, we may need to show an error dialog.
      if (mCallList != null && mCallList.getDisconnectedCall() != null) {
        maybeShowErrorDialogOnDisconnect(mCallList.getDisconnectedCall());
      }

      // When the UI comes up, we need to first check the in-call state.
      // If we are showing NO_CALLS, that means that a call probably connected and
      // then immediately disconnected before the UI was able to come up.
      // If we dont have any calls, start tearing down the UI instead.
      // NOTE: This code relies on {@link #mInCallActivity} being set so we run it after
      // it has been set.
      if (mInCallState == InCallState.NO_CALLS) {
        Log.i(this, "UI Intialized, but no calls left.  shut down.");
        attemptFinishActivity();
        return;
      }
    } else {
      Log.i(this, "UI Destroyed)");
      updateListeners = true;
      mInCallActivity = null;

      // We attempt cleanup for the destroy case but only after we recalculate the state
      // to see if we need to come back up or stay shut down. This is why we do the cleanup
      // after the call to onCallListChange() instead of directly here.
      doAttemptCleanup = true;
    }

    // Messages can come from the telephony layer while the activity is coming up
    // and while the activity is going down.  So in both cases we need to recalculate what
    // state we should be in after they complete.
    // Examples: (1) A new incoming call could come in and then get disconnected before
    //               the activity is created.
    //           (2) All calls could disconnect and then get a new incoming call before the
    //               activity is destroyed.
    //
    // b/1122139 - We previously had a check for mServiceConnected here as well, but there are
    // cases where we need to recalculate the current state even if the service in not
    // connected.  In particular the case where startOrFinish() is called while the app is
    // already finish()ing. In that case, we skip updating the state with the knowledge that
    // we will check again once the activity has finished. That means we have to recalculate the
    // state here even if the service is disconnected since we may not have finished a state
    // transition while finish()ing.
    if (updateListeners) {
      onCallListChange(mCallList);
    }

    if (doAttemptCleanup) {
      attemptCleanup();
    }
  }