Android Quickstart: Receiving Incoming Calls

Now that we know how your app initiates outgoing Connections, let's spend some time looking at incoming Connections.

To receive incoming connections, a Client app needs to do the following:

  1. The Device object must be registered with a client 'name'
  2. The app must implement callbacks that notify of incoming connections via listener methods

Register with a Client Name

Our app satisfies (1) by sending a client name to the server when it requests a token, as we've seen in previous steps. You can change the client name being sent to the server by clicking the button in thetop right of the screen:

Change Client name

DeviceListener Callbacks

Device announces the important events to an object that implements the DeviceListener interface:

public void onStartListening(Device inDevice);

  • callback for when the device is successfully registered with Twilio

public void onStopListening(Device inDevice);

  • callback for when the device is no longer listening for incoming connections due to an explicit request to stop

public void onStopListening(Device inDevice, int inErrorCode, String inErrorMessage);

  • callback for when the device is no longer listening for incoming connections due to an error

The Quickstart app implements these callbacks in ClientActivity.java

ClientActivity.java
public class ClientActivity implements DeviceListener
{
    /* Device Listener */
    @Override
    public void onStartListening(Device device) {
        Log.d(TAG, "Device has started listening for incoming connections");
    }

    /* Device Listener */
    @Override
    public void onStopListening(Device device) {
        Log.d(TAG, "Device has stopped listening for incoming connections");
    }

    /* Device Listener */
    @Override
    public void onStopListening(Device device, int errorCode, String error) {
        Log.e(TAG, String.format("Device has encountered an error and has stopped" +
                " listening for incoming connections: %s", error));
    }
}

Actually accepting the incoming connection is a little bit more work.

Handling Incoming Connections with Intention

Incoming Connections are detected by the Twilio Client service and handed to your app. The mechanism to notify your app of incoming Connections, whether it is in the foreground or background, is a PendingIntent. You need to provide a PendingIntent to each Twilio Client Device via Device.setIncomingIntent(). This object wraps an Intent that describes the Android component to be triggered when an incoming Connection is received. The Twilio Client service is agnostic to the Android component: Activity, Service, or BroadcastReciever.

What you do when you receive this Intent depends on the component you set in the Intent:

When you receive the Intent, you can retrieve the Device and Connection for the incoming Connection using Intent.getParcelableExtra(), using Device.EXTRA_DEVICE and Device.EXTRA_CONNECTION as keys, respectively.

Suggestion: Keep your Device(s) in a singleton object outside of a particular activity context.

The following code snippet (a modified verison of the Quickstart) illustrates a pattern for handling incoming Connections in single-activity application.

public class ClientActivity implements DeviceListener, ConnectionListener {

    private void createDevice(String capabilityToken) {
          clientDevice = Twilio.createDevice(capabilityToken, ClientActivity.class);
          Intent intent = new Intent(getApplicationContext(), ClientActivity.class);
          PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
          clientDevice.setIncomingIntent(pendingIntent);
    }

    /*
     * Receive intent for incoming call from Twilio Client Service
     * Android will only call Activity.onNewIntent() if `android:launchMode` is set to `singleTop`.
     */
    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    @Override
    public void onResume() {
        super.onResume();

        Intent intent = getIntent();

        if (intent != null) {
            /*
             * Determine if the receiving Intent has an extra for the incoming connection. If so,
             * remove it from the Intent to prevent handling it again next time the Activity is resumed
             */
            Device device = intent.getParcelableExtra(Device.EXTRA_DEVICE);
            Connection incomingConnection = intent.getParcelableExtra(Device.EXTRA_CONNECTION);

            if (incomingConnection == null && device == null) {
                return;
            }
            intent.removeExtra(Device.EXTRA_DEVICE);
            intent.removeExtra(Device.EXTRA_CONNECTION);

            // Application Specific Logic for handling an incoming Connection
            handleIncomingConnection(Device device, Connection incoming);
        }
    }


}

Configure a Twilio Phone Number to Receive Calls

The Quickstart app is fully capable of receiving a call from a real phone. However, we first need a phone number for our friends to call us at. To do this, provision a Twilio phone number, (or use a Twilio phone number you've already purchased) and configure the Voice URL to once again point at your web server's '/call' URL, e.g. https://bosco-baracus-1201.herokuapp.com/call

The python server that we set up earlier is smart enough to determine that the incoming call is from a regular phone and should be routed to the Twilio Client name that you have hard-coded in server.py - it defaults to 'jenny'.

Call your Twilio number and you should be connected to your device (or Android Emulator, whichever you're running), which will automatically answer the call. Enjoy the chat - you're great company.

Wrapping up

That's it for this Quickstart! If you want to learn more about how to customize the telephony experience of your application, check out the TwiML documentation and the Twilio Client Android Docs.

We can't wait to see what you build.