Get Started

Twilio Client SDK for Android Quickstart

Receiving Incoming Connections

Now that we know how to initiate connections from your app, it's time for your app to start receiving incoming connections. By the end of this tutorial, you will be able to call IN to your device using the Android Emulator (or vice-versa). Hold on tight...

To receive incoming connections, we'll do the following things:

  1. Give the app client a name and "register" it with Twilio.
  2. Add callbacks to notify your app of incoming connections via listener methods.
  3. Write some TwiML to <Dial> your named <Client>.

First, start by modifying your auth.php file to accept a clientName parameter (replacing the hard-coded value of "monkey"):

auth.php
<?php

// Found in the 'helper-libs' folder, or download twilio-php from http://twilio.com/docs/libraries
require "Services/Twilio/Capability.php";

$accountSid = "ACXXXXXXXXXXXXXXXX";
$authToken = "secret";

// The app outgoing connections will use:
$appSid = "APXXXXXXXXXXXXXXXXXXXXXXXXX"; // YOUR APPLICATION SID!

// The client name for incoming connections:
$clientName = $_REQUEST["clientName"];

$capability = new Services_Twilio_Capability($accountSid, $authToken);

// This allows incoming connections as $clientName:
$capability->allowClientIncoming($clientName);

// This allows outgoing connections to $appSid with the "From"
// parameter being the value of $clientName
$capability->allowClientOutgoing($appSid, array(), $clientName);

// This returns a token to use with Twilio based on
// the account and capabilities defined above
$token = $capability->generateToken();

echo $token;
?>

And change MonkeyPhone to pass this client name to the PHP file when it starts up. (In a real app, you would likely pass a username/password combination that the user would enter, but we'll omit this for simplicity.)

MonkeyPhone.java
public class MonkeyPhone implements Twilio.InitListener
{
    /* ... other methods ... */

    /* Twilio.InitListener method */
    @Override
    public void onInitialized()
    {
        Log.d(TAG, "Twilio SDK is ready");

        try {
            String capabilityToken = HttpHelper.httpGet("http://companyfoo.com/auth.php?clientName=jenny");
            device = Twilio.createDevice(capabilityToken, null);
        } catch (Exception e) {
            Log.e(TAG, "Failed to obtain capability token: " + e.getLocalizedMessage());
        }
    }

    /* ... other methods ... */
}

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

public boolean receivePresenceEvents(Device inDevice);

  • called to determine if your application wants to receive presence events: if you don't use presence, you can save your users a little bandwidth and battery life by returning false here

public void onPresenceChanged(Device inDevice, PresenceEvent inPresenceEvent);

  • called when any client on your account becomes available or unavailable

We'll modify MonkeyPhone to implement these methods. First we'll declare the interface and register the instance of MonkeyPhone to be the Device's listener when we create it, and then we'll define the three DeviceListener methods. We don't need to take any action here, but we'll log the various state transitions and any errors.

MonkeyPhone.java
public class MonkeyPhone implements Twilio.InitListener, DeviceListener
{
    /* ... other methods ... */

    /* Twilio.InitListener method */
    @Override
    public void onInitialized()
    {
        Log.d(TAG, "Twilio SDK is ready");

        try {
            String capabilityToken = HttpHelper.httpGet("http://companyfoo.com/auth.php?clientName=jenny");
            device = Twilio.createDevice(capabilityToken, this);
        } catch (Exception e) {
            Log.e(TAG, "Failed to obtain capability token: " + e.getLocalizedMessage());
        }
    }

    /* ... other methods ... */

    @Override /* DeviceListener method */
    public void onStartListening(Device inDevice)
    {
        Log.i(TAG, "Device is now listening for incoming connections");
    }

    @Override /* DeviceListener method */
    public void onStopListening(Device inDevice)
    {
        Log.i(TAG, "Device is no longer listening for incoming connections");
    }

    @Override /* DeviceListener method */
    public void onStopListening(Device inDevice, int inErrorCode, String inErrorMessage)
    {
        Log.i(TAG, "Device is no longer listening for incoming connections due to error " +
                   inErrorCode + ": " + inErrorMessage);
    }

    @Override /* DeviceListener method */
    public boolean receivePresenceEvents(Device inDevice)
    {
        return false;  // indicate we don't care about presence events
    }

    @Override /* DeviceListener method */
    public void onPresenceChanged(Device inDevice, PresenceEvent inPresenceEvent) { }

    /* ... other methods ... */
}

Actually accepting the incoming connection is a little bit more work. You might want to glance at the section of the Getting Started Guide (included with the documentation in the SDK download) that deals with incoming connections for some background on why this is the case. What it boils down to is:

  1. Create a PendingIntent that can activate HelloMonkeyActivity.
  2. Register this PendingIntent using Device.setIncomingIntent().
  3. Provide a hook in MonkeyPhone to handle the incoming call.
  4. Implement onNewIntent() in HelloMonkeyActivity to update the activity's Intent.
  5. Implement onResume() in HelloMonkeyActivity to check to see if we have an incoming connection, and handle it if so.

So for the first half:

MonkeyPhone.java
public class MonkeyPhone implements Twilio.InitListener, DeviceListener
{
    private Context context;
    private Device device;
    private Connection connection;

    public MonkeyPhone(Context context)
    {
        this.context = context;
        Twilio.initialize(context, this /* Twilio.InitListener */);
    }

    /* ... other methods ... */

    /* Twilio.InitListener method */
    @Override
    public void onInitialized()
    {
        Log.d(TAG, "Twilio SDK is ready");

        try {
            String capabilityToken = HttpHelper.httpGet("http://companyfoo.com/auth.php?clientName=jenny");
            device = Twilio.createDevice(capabilityToken, this);

            Intent intent = new Intent(context, HelloMonkeyActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            device.setIncomingIntent(pendingIntent);
        } catch (Exception e) {
            Log.e(TAG, "Failed to obtain capability token: " + e.getLocalizedMessage());
        }
    }

    /* ... other methods ... */

    public void handleIncomingConnection(Device inDevice, Connection inConnection)
    {
        Log.i(TAG, "Device received incoming connection");
        if (connection != null)
            connection.disconnect();
        connection = inConnection;
        connection.accept();
    }

    /* ... other methods ... */
}

And for the second half:

HelloMonkeyActivity.java
public class HelloMonkeyActivity extends Activity implements View.OnClickListener
{
    /* ... other methods... */

    @Override
    public void onNewIntent(Intent intent)
    {
        super.onNewIntent(intent);
        setIntent(intent);
    }

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

        Intent intent = getIntent();
        Device device = intent.getParcelableExtra(Device.EXTRA_DEVICE);
        Connection connection = intent.getParcelableExtra(Device.EXTRA_CONNECTION);
        if (device != null && connection != null) {
            intent.removeExtra(Device.EXTRA_DEVICE);
            intent.removeExtra(Device.EXTRA_CONNECTION);
            phone.handleIncomingConnection(device, connection);
        }
    }

    /* ... other methods... */
}

If you build and run the app, it's now ready to receive incoming calls. Now we need to provision a Twilio phone number, and configure the Voice URL to point to a simple TwiML file which we will create and name: call-jenny.xml.

call-jenny.xml
<Response>
    <Dial>
        <Client>jenny</Client>
    </Dial>
</Response>

If you put this file at the root of your companyfoo.com web site, you can change your Voice URL for your Twilio App to be http://companyfoo.com/call-jenny.xml.

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. Start talkin'.

Ready to put it all together?


Next: Making Calls In and Out of Your App »