What happens at the system level on an incoming call?

android, telephony

Solution

Let's begin by looking at CallNotifier:

/** * Phone app module that listens for phone state changes and various other * events from the telephony layer, and triggers any resulting UI behavior * (like starting the Ringer and Incoming Call UI, playing in-call tones, * updating notifications, writing call log entries, etc.) */

One of the messages that this Handler responds to is: `CallStateMonitor.PHONE_NEW_RINGING_CONNECTION`:

case CallStateMonitor.PHONE_NEW_RINGING_CONNECTION:
    log("RINGING... (new)");
    onNewRingingConnection((AsyncResult) msg.obj);
    mSilentRingerRequested = false;
    break;

`onNewRingingConnection(AsyncResult)` eventually (and, in general case) calls `ringAndNotifyOfIncomingCall(Connection c)`:

private void ringAndNotifyOfIncomingCall(Connection c) {
    if (PhoneUtils.isRealIncomingCall(c.getState())) {
        mRinger.ring();
    } else {
        if (VDBG) log("- starting call waiting tone...");
            if (mCallWaitingTonePlayer == null) {
                mCallWaitingTonePlayer = new InCallTonePlayer(
                                         InCallTonePlayer.TONE_CALL_WAITING);
                mCallWaitingTonePlayer.start();
            }
    }

    // CallModeler.onNewRingingConnection(Connection)
    mCallModeler.onNewRingingConnection(c);
}

`CallModeler.onNewRingingConnection(Connection)` (Link) notifies attached listeners:

for (int i = 0; i < mListeners.size(); ++i) {
    mListeners.get(i).onIncoming(call);
}

These listeners implement `CallModeler.Listener` interface. CallHandlerServiceProxy is one such listener, and its `onIncoming(Call)` callback fires `CallHandlerServiceProxy.processIncoming(Call)`:

private void processIncoming(Call call) {
    ....
    // ICallHandlerService
    mCallHandlerServiceGuarded.onIncoming(call,
                   RejectWithTextMessageManager.loadCannedResponses());
    ....
}

CallHandlerService defines a `ICallHandlerService.Stub` member and its `onIncoming(Call, List<String>)` method looks like:

@Override
public void onIncoming(Call call, List<String> textResponses) {
    ....
    mMainHandler.sendMessage(mMainHandler.obtainMessage(
                   ON_UPDATE_CALL_WITH_TEXT_RESPONSES, incomingCall));
    ....
}

This is how `mMainHandler` handles case `ON_UPDATE_CALL_WITH_TEXT_RESPONSES`:

case ON_UPDATE_CALL_WITH_TEXT_RESPONSES:
    AbstractMap.SimpleEntry<Call, List<String>> entry
                   = (AbstractMap.SimpleEntry<Call, List<String>>) msg.obj;
    Log.i(TAG, "ON_INCOMING_CALL: " + entry.getKey());

    // CallList
    mCallList.onIncoming(entry.getKey(), entry.getValue());
    break;

CallList keeps a list of listeners that implement `CallList.Listener`, and fires their `onIncomingCall(Call)` event from its `CallList.onIncoming(Call, List<String>)` method.

Now, let's look at InCallPresenter:

/** * Takes updates from the CallList and notifies the InCallActivity (UI) * of the changes. * Responsible for starting the activity for a new call and finishing the activity when all calls * are disconnected. * Creates and manages the in-call state and provides a listener pattern for the presenters * that want to listen in on the in-call state changes. * TODO: This class has become more of a state machine at this point. Consider renaming. */

`InCallPresenter` implements `CallList.Listener` interface, and is responsible for launching `InCallActivity` that provides the UI for all phone related operations. The following comment (taken from `InCallPresenter.startOrFinishUi(InCallState)`) brings the above-mentioned chain of events together:

/* A new Incoming call means that the user needs to be notified of the
   the call (since it wasn't them who initiated it).  We do this 
   through full  screen notifications and happens indirectly through {@link 
   StatusBarListener}. The process for incoming calls is as follows:

   1) CallList          - Announces existence of new INCOMING call
   2) InCallPresenter   - Gets announcement and calculates that the new 
                          InCallState should be set to INCOMING.
   3) InCallPresenter   - This method is called to see if we need to 
                          start or finish the app given the new state.
   4) StatusBarNotifier - Listens to InCallState changes. InCallPresenter 
                          calls StatusBarNotifier explicitly to issue a 
                          FullScreen Notification that will either start the
                          InCallActivity or show the user a top-level 
                          notification dialog if the user is in 
                          an immersive app. That notification can also start 
                          the InCallActivity.         
   5) InCallActivity    - Main activity starts up and at the end of its 
                          onCreate will call InCallPresenter::setActivity() 
                          to let the presenter know that start-up is complete.
                  [ AND NOW YOU'RE IN THE CALL. voila! ] */

I hope this answers your question, or at the very least, shows you where to look. Feel free to correct anything I overlooked/misinterpreted.

Problem

I've downloaded the entire source code for the master branch from https://android.googlesource.com/platform/frameworks/base/+/master, and am trying to decipher the chain of events on an incoming call. I assume that the ACTION_ANSWER intent is started but beyond that don't know what happens before or after. Can anyone help?

Original source