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:
<Dial> your named <Client>.First, start by modifying your auth.php file to accept a clientName
parameter (replacing the hard-coded value of "monkey"):
<?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.)
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);
public void onStopListening(Device inDevice);
public void onStopListening(Device inDevice, int inErrorCode, String inErrorMessage);
public boolean receivePresenceEvents(Device inDevice);
false herepublic void onPresenceChanged(Device inDevice, PresenceEvent inPresenceEvent);
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.
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:
PendingIntent that can activate HelloMonkeyActivity.PendingIntent using Device.setIncomingIntent().MonkeyPhone to handle the incoming call.onNewIntent() in HelloMonkeyActivity to update the
activity's Intent.onResume() in HelloMonkeyActivity to check to see if we
have an incoming connection, and handle it if so.So for the first half:
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:
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_CONNECTI
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.
<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?