Twilio Client for Android Quickstart Tutorial

Experiment with the Pre-Built App

Overview of the Android App

Let's start by opening the downloaded/cloned project in Android Studio. To do this, select "Open an Existing Android Studio Project" from the Android Studio launch screen, then navigate to the folder where you extracted the project.

The Quickstart app is very simple. There is a text field where you can enter a phone number (or the name of another Twilio Client - not covered in this tutorial) that you'd like to call, and a few buttons to make the magic happen.

The app is designed to work out of the box. If you'd like to start using it immediately, substitute the value of TOKEN_SERVICE_URL for the Capability Token service that we deployed in the previous step. That way you can discover all the functionality of the app yourself.

For example, in ClientActivity.java:

private static final String TOKEN_SERVICE_URL = "https://bosco-baracus-1201.herokuapp.com/token";

To experience the app's full functionality, you'll also need to change the Voice Request URL of your TwiML App to point at your web server's '/call' endpoint, e.g. https://bosco-baracus-1201.herokuapp.com/call

Ready to go!

Working Quickstart App

Understanding the Code

For the remainder of this tutorial however, we're going to assume that you're here to learn about the main concepts of the SDK code. We will walk step-by-step through what makes the Quickstart app tick. And for that, you should start by resetting your TwiML App's Voice Request URL to your web server's root URL, e.g. https://bosco-baracus-1201.herokuapp.com/

Creating a Device

The primary class for connecting to Twilio services from your app is Device. It represents a soft "device" that knows how to speak to Twilio services, coordinates service authorization with Twilio, listens for incoming connections, and establishes outgoing connections. An instance of this class is created using a "Capability Token", described in the next section.

You'll use a Device to initiate outgoing calls and listen for incoming calls. Let's look at how the Quickstart app creates a Device and wires it up.

ClientActivity.java

/*
 * Create a Device or update the capabilities of the current Device
 */
private void createDevice(String capabilityToken) {
    try {
        if (clientDevice == null) {
            clientDevice = Twilio.createDevice(capabilityToken, this);
​
            /*
             * Providing a PendingIntent to the newly create Device, allowing you to receive incoming calls
             *
             *  What you do when you receive the intent depends on the component you set in the Intent.
             *
             *  If you're using an Activity, you'll want to override Activity.onNewIntent()
             *  If you're using a Service, you'll want to override Service.onStartCommand().
             *  If you're using a BroadcastReceiver, override BroadcastReceiver.onReceive().
             */
​
            Intent intent = new Intent(getApplicationContext(), ClientActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
            clientDevice.setIncomingIntent(pendingIntent);
        } else {
            clientDevice.updateCapabilityToken(capabilityToken);
        }
​            
        ...
​
    } catch (Exception e) {
        Log.e(TAG, "An error has occured updating or creating a Device: \n" + e.toString());
        Toast.makeText(ClientActivity.this, "Device error", Toast.LENGTH_SHORT).show();
    }
}

The code above creates a Twilio Client Device object and sets the Device Listener to the current Activity.

The Device Listener is responsible for handling events like onStartListening and onStopListening, which will inform you when your application is listening for incoming Calls (Connections) from Twilio.

Fetching a Capability Token

In the previous example, we passed a "Capability Token" to our Device Constructor. But what is a Capability Token and where did it come from? Capability tokens allow you to add Twilio capabilities to web and mobile applications without exposing your super secret Auth Token in JavaScript or any other client-side environment.

  • Your server provides a Capability Token to each client.
  • Each token contains specific information that enables Twilio to identify that the client belongs to your Twilio account, and what permissions ('capabilities') you have granted this user.
  • The easiest way to generate a Capability Token is using a Twilio server-side Helper Library.

A Capability Token is technically a JWT Token. Learn more about Capability Tokens.

ClientActivity.java
/*
 * Request a Capability Token from your public accessible server
 */
private void retrieveCapabilityToken(final ClientProfile newClientProfile) {

    // Correlate desired properties of the Device (from ClientProfile) to properties of the Capability Token
    // Correlate desired properties of the Device (from ClientProfile) to properties of the Capability Token
    Uri.Builder b = Uri.parse(TOKEN_SERVICE_URL).buildUpon();
    if (newClientProfile.isAllowOutgoing()) {
        b.appendQueryParameter("allowOutgoing", newClientProfile.allowOutgoing ? "true" : "false");
    }
    if (newClientProfile.isAllowIncoming() && newClientProfile.getName() != null) {
        b.appendQueryParameter("client", newClientProfile.getName());
    }

    Ion.with(getApplicationContext())
            .load(b.toString())
            .asString()
            .setCallback(new FutureCallback() {
                @Override
                public void onCompleted(Exception e, String capabilityToken) {
                    if (e == null) {
                        Log.d(TAG, capabilityToken);

                        // Update the current Client Profile to represent current properties
                        ClientActivity.this.clientProfile = newClientProfile;

                        // Create a Device with the Capability Token
                        createDevice(capabilityToken);
                    } else {
                        Log.e(TAG, "Error retrieving token: " + e.toString());
                        Toast.makeText(ClientActivity.this, "Error retrieving token", Toast.LENGTH_SHORT).show();
                    }
                }
            });
}

Making an HTTP request to the /token endpoint of the Quickstart web-server returns a Capability Token, which, when provided to a Device constructor, grants the new Device capabilities such as making outgoing calls or allowing incoming calls.

Our particular server configuration allows us to specify what permissions will be included in the token by appending query string parameters. In a production application, capabilities are determined by the server, probably based on an existing authentication system.

For the security of your Twilio account, you should not embed a Capability Token or your Twilio Account's Auth Token in the app you submit to the Google Play Store.

Dialing Out

Once our Device has been created and initialized, we can make an outgoing call (aka Connection) request. To create a Connection, we call the Device.connect() method.

Before initiating the outbound call we should take a second to understand what will happen when we call the Device.connect() method. When we generated our Capability Token on the server, we encoded an AppSid configuration parameter. This maps to the TwiML App we created earlier. When we call connect(), an Audio connection will be established from our Device to Twilio. Twilio will then make a request to the Voice Request URL of our TwiML App, expecting to find instructions on how to handle the call.

If we create a Connection right now, regardless of what client name or phone number we enter in the text field, we will simply hear "Welcome to Twilio". Give it a shot. In the next step, we will learn why that is.

The Quickstart code that creates the outbound Connection is inside our Activity's connect method:

ClientActivity.java
private void connect(String contact, boolean isPhoneNumber) {
    ...

    Map params = new HashMap();
    params.put("To", contact);

    if (clientDevice != null) {
        // Create an outgoing connection
        connection = clientDevice.connect(params, this);
        setCallUI();
    } else {
        Toast.makeText(ClientActivity.this, "No existing device", Toast.LENGTH_SHORT).show();
    }
}

In the next few steps we will implement more interesting call flows by changing our Voice Request URL. First, let's understand what is really happening on the server that we already implemented.


Next: Connecting to a TwiML Application »