Get Started

Twilio Client SDK for Android Quickstart

Make Outgoing Calls

The Eclipse project

Next, open the "HelloMonkey" project in Eclipse (File -> Import -> General -> Existing Projects into Workspace).

The HelloMonkey app is very simple, presenting "Dial" and "Hangup" buttons, and a text field for who the app should call. The user interface elements have already been wired up to the HelloMonkeyActivity class but don't actually do anything (yet).

First let's run through the code and figure out what everything does.

Classes

The MonkeyPhone class is going to be our central coordinator object that talks to the Twilio Client APIs, and this is where the bulk of the functionality will live.

The MonkeyPhoneActivity class is the Android application's main Activity that will instantiate MonkeyPhone and respond to user input events.

The HttpHelper class is a simple wrapper around Apache HttpClient (included with the Android SDK) that'll make it easier to fetch HTTP URLs. In your real application, you'll want to do something similar, but handle downloading asynchronously, in another thread, to avoid blocking the main UI thread.

Initializing the SDK and Creating a Device

Before doing anything, you must first initialize the Twilio Client SDK. This happens asynchronously, and you'll get notified via a Listener when the SDK is up and running. The call to Twilio.initialize() in the constructor of MonkeyPhone takes care of this. You'll get notified of success or failure via the Twilio.InitListener interface, which the MonkeyPhone class also implements.

In the onInitialized() method, we create an instance of the com.twilio.client.Device class using the factory method Twilio.createDevice(). An instance of Device represents a soft "device" that knows how to speak to Twilio services. You'll use a Device to initiate outgoing calls and listen for incoming calls. Here's what the base MonkeyPhone class looks like:

MonkeyPhone.java
import com.twilio.client.Device;
import com.twilio.client.Twilio;

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

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

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

    @Override /* Twilio.InitListener method */
    public void onError(Exception e)
    {
        Log.e(TAG, "Twilio SDK couldn't start: " + e.getLocalizedMessage());
    }

    @Override
    protected void finalize()
    {
        if (device != null)
            device.release();
    }
}

Note that the URL we're fetching is on a server called "companyfoo.com". You'll want to change that URL to point to where you stored auth.php on your server.

For the security of your Twilio Account, you should never store a capability token string or your Twilio AuthToken as a part of the app you distribute on the Android Market.

The HelloMonkeyActivity class is pretty simple at this point: all it does is set up the UI view, fetch some widget references, and instantiate an instance of MonkeyPhone:

HelloMonkeyActivity.java
public class HelloMonkeyActivity extends Activity implements View.OnClickListener
{
    private MonkeyPhone phone;
    private EditText numberField;

    @Override
    public void onCreate(Bundle bundle)
    {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        phone = new MonkeyPhone(getApplicationContext());

        ImageButton dialButton = (ImageButton)findViewById(R.id.dialButton);
        dialButton.setOnClickListener(this);

        ImageButton hangupButton = (ImageButton)findViewById(R.id.hangupButton);
        hangupButton.setOnClickListener(this);

        numberField = (EditText)findViewById(R.id.numberField);
    }

    @Override
    public void onClick(View view)
    {
        if (view.getId() == R.id.dialButton)
            phone.connect();
    }
}

Important note: we recommend that you pass Application context (and not Activity context) to Twilio SDK functions. The SDK internals that need a reference to a Context instance will likely live beyond the lifecycle of any individual Activity. See the article Avoiding Memory Leaks for more information on why this matters.

There's one more thing that we need to do before it will run. Due to how Android handles background apps, the SDK uses an Android Service behind the scenes. This service needs to be declared in your AndroidManifest.xml file inside the <application> tag like so:

AndroidManifest.xml
<!-- ... other XML stuff... -->

    <application
      android:icon="@drawable/ic_launcher"
      android:label="@string/app_name">
        <activity
          android:label="@string/app_name"
          android:name="com.twilio.example.hellomonkey.HelloMonkeyActivity"
          android:screenOrientation="portrait">
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
          android:name="com.twilio.client.TwilioClientService"
          android:exported="false" />

    </application>

<!-- ... other XML stuff... -->

Take special note of the android:exported="false" attribute. This is necessary to avoid interfering with other applications built using the Twilio Client SDK. The SDK will refuse to initialize if it detects that this attribute is missing.

While you have the manifest open, take a look at the <uses-permission> tags. These are all required when using the Twilio Client SDK, so don't forget to add them to your own applications.

If you compile and run this code, you should see the following:

Hello Monkey Screenshot

Now we've got an app that can create outgoing connections and receive incoming connections.

For the time being we'll focus on making an outgoing connection. The connection will call a Twilio sample application that responds with a friendly greeting.

Dialing Out

In this section of the Quickstart, we'll be:

  1. Making MonkeyPhone able to call out, and
  2. Hooking up one of the buttons in the UI.

Let's add a method to MonkeyPhone to initiate a connection. We'll keep track of the connection we've created as a member variable of type Connection. To make a connection, we call the Device.connect() method. Just pass in null parameters and a null listener for the moment; we'll do more with these arguments later.

MonkeyPhone.java
import com.twilio.client.Connection;
import com.twilio.client.Device;
import com.twilio.client.Twilio;

public class MonkeyPhone implements Twilio.InitListener
{
    private Device device;
    private Connection connection;

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

    public void connect()
    {
        connection = device.connect(null /* parameters */, null /* ConnectionListener */);
        if (connection == null)
            Log.w(TAG, "Failed to create new connection");
    }

    @Override
    protected void finalize()
    {
        if (connection != null)
            connection.disconnect();
        if (device != null)
            device.release();
    }
}

Note that we do a null check on the returned Connection object after calling connect(). There are some cases where creating a new connection can fail.

If you take a look at HelloMonkeyActivity, you'll notice it has a member variable called phone of type MonkeyPhone. When the activity is launched, it initializes a MonkeyPhone object and sets it as the value of the phone member.

There's also an empty onClick() handler for the dial and hangup buttons. When the dial button is pressed, we (obviously) want to dial out. Let's use the MonkeyPhone instance to do that:

HelloMonkeyActivity.java:

public class HelloMonkeyActivity extends Activity implements View.OnClickListener
{
    private MonkeyPhone phone;

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

    @Override
    public void onClick(View view)
    {
        if (view.getId() == R.id.dialButton)
            phone.connect();
    }
}

If you now compile the app and run it, you should be able to click the "Dial" button and hear the greeting. Awesome!

Wouldn't it be nice if you could also hang up on a connection if you don't want to hear the whole thing? Let's go do that now.


Next: Hanging Up from Your Android Device »