Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens at the system level on an incoming call?

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?

like image 802
Bachalo Avatar asked Jan 10 '14 20:01

Bachalo


2 Answers

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.

like image 114
Vikram Avatar answered Sep 20 '22 03:09

Vikram


have a look at this Grep code InCallScreen.java

   else if (action.equals(Intent.ACTION_ANSWER)) {
        internalAnswerCall();
        app.setRestoreMuteOnInCallResume(false);
        return InCallInitStatus.SUCCESS;
like image 27
LOG_TAG Avatar answered Sep 22 '22 03:09

LOG_TAG