14. Using Android Telephony APIs

Although the Android platform has been designed to run on almost any type of device, many of the Android devices currently available on the market are smartphones. Applications can take advantage of this fact by integrating phone or telephony features into their feature set. This chapter introduces you to the telephony-related APIs available in the Android SDK.

Working with Telephony Utilities

The Android SDK provides a number of useful utilities to integrate phone features available on the device with applications. Although devices run applications, phone operations generally take precedence on smartphones. Your application should not interrupt a phone conversation, for example. To avoid this kind of behavior, your application should know something about what the user is doing, so that it can react differently. For instance, an application might query the state of the phone and determine that the user is talking on the phone, and then choose to vibrate instead of play an alarm.


Image Tip

There are many different types of Android devices now available to consumers. If your application uses telephony features, make sure you set the <uses-feature> tag with the android.hardware.telephony feature (or one of its sub-features) in your application’s manifest file to ensure that your application is installed only on compatible devices. See the Android SDK documentation for more details.


In other cases, applications might need to place a call or send a text message. Phones typically support SMS, which is popular for texting (text messaging). Enabling the capability to leverage this feature from an application can enhance the appeal of the application and add features that can’t be easily replicated on a desktop environment. Because many Android devices are phones, applications frequently deal with phone numbers and the contacts database; some might want to access the phone dialer to place calls or check phone status information. Adding telephony features to an application enables a more integrated user experience and enhances the overall value of the application to the users.


Image Tip

Many of the code examples provided in this chapter are taken from the SimpleTelephony application. The source code for this application is provided for download on the book’s website.


Gaining Permission to Access Phone State Information

Let’s begin by looking at how to determine the telephony state of the device, including the capability to request the hook state of the phone, information about the phone service, and utilities for handling and verifying phone numbers. The TelephonyManager object in the android.telephony package is a great place to start.

Many of the method calls in this section require explicit permission set with the Android application manifest file. The READ_PHONE_STATE permission is required to retrieve information such as the call state, handset phone number, and device identifiers or serial numbers. The ACCESS_COARSE_LOCATION permission is required for cellular location information.

The following block of XML is typically needed in an application’s AndroidManifest.xml file to access basic phone state information:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Requesting Call State

You can use the TelephonyManager object to retrieve the state of the phone and some information about the phone service itself, such as the phone number of the handset.

You can request an instance of TelephonyManager using the getSystemService() method, like this:

TelephonyManager telManager = (TelephonyManager)
    getSystemService(Context.TELEPHONY_SERVICE);

With a valid TelephonyManager instance, an application can now make several queries. One important method is getCallState(). This method can determine the voice call status of the handset. The following block of code shows how to query for the call state and all the possible return values:

int callStatus = telManager.getCallState();
String callState = null;

switch (callStatus) {

    case TelephonyManager.CALL_STATE_IDLE:
        callState = "Phone is idle.";
        break;

    case TelephonyManager.CALL_STATE_OFFHOOK:
        callState = "Phone is in use.";
        break;

    case TelephonyManager.CALL_STATE_RINGING:
        callState = "Phone is ringing!";
        break;
}
Log.i("telephony", callState);

The three call states can be simulated with the emulator through the Dalvik Debug Monitor Service (DDMS) tool. Querying for the call state can be useful in certain circumstances. However, listening for changes in the call state can enable an application to react appropriately to something the user might be doing. For instance, a game might automatically pause and save state information when the phone rings so that the user can safely answer the call. An application can register to listen for changes in the call state by making a call to the listen() method of TelephonyManager:

telManager.listen(new PhoneStateListener() {
    public void onCallStateChanged(
        int state, String incomingNumber) {

        String newState = getCallStateString(state);
        if (state == TelephonyManager.CALL_STATE_RINGING) {
            Log.i("telephony", newState +
                " number = " + incomingNumber);
        } else {
            Log.i("telephony", newState);
        }
    }
}, PhoneStateListener.LISTEN_CALL_STATE);

The listener is called, in this case, whenever the phone starts ringing, the user makes a call, the user answers a call, or a call is disconnected. The listener is also called right after it is assigned so an application can get the initial state.

Another useful piece of information is determining the state of the telephony service. This information can tell an application if the phone has coverage at all, if it can make emergency calls only, or if the radio for phone calls is turned off as it might be when in airplane mode. To do this, an application can add the PhoneStateListener.LISTEN_SERVICE_STATE flag to the listener described earlier and implement the onServiceStateChanged method, which receives an instance of the ServiceState object. Alternatively, an application can check the state by constructing a ServiceState object and querying it directly, as shown here:

int serviceStatus = serviceState.getState();
String serviceStateString = null;

switch (serviceStatus) {
    case ServiceState.STATE_EMERGENCY_ONLY:
        serviceStateString = "Emergency calls only";
        break;

    case ServiceState.STATE_IN_SERVICE:
        serviceStateString = "Normal service";
        break;

    case ServiceState.STATE_OUT_OF_SERVICE:
        serviceStateString = "No service available";
        break;

    case ServiceState.STATE_POWER_OFF:
        serviceStateString = "Telephony radio is off";
        break;
}
Log.i("telephony", serviceStateString);

A status such as whether the handset is roaming can be determined by a call to the getRoaming() method. A friendly and frugal application can use this method to warn the user before performing any costly roaming operations such as data transfers within the application.

Requesting Service Information

In addition to call and service state information, your application can retrieve other information about the device. This information is less useful for the typical application but can diagnose problems or provide specialized services available only from certain provider networks. The following code retrieves several pieces of service information:

String opName = telManager.getNetworkOperatorName();
Log.i("telephony", "operator name = " + opName);

String phoneNumber = telManager.getLine1Number();
Log.i("telephony", "phone number = " + phoneNumber);

String providerName = telManager.getSimOperatorName();
Log.i("telephony", "provider name = " + providerName);

The network operator name is the descriptive name of the current provider that the handset connects to, typically the current tower operator. The SIM operator name is typically the name of the user’s service provider. The phone number for this API is defined as the MSISDN, typically the directory number of a GSM handset (that is, the number someone would dial to reach that particular phone).

Monitoring Signal Strength and Data Connection Speed

Sometimes an application might want to alter its behavior based on the signal strength or service type of the device. For example, a high-bandwidth application might alter stream quality or buffer size based on whether the device has a low-speed connection (such as 1xRTT or EDGE) or a high-speed connection (such as EVDO or HSDPA). TelephonyManager can be used to determine such information.

If your application needs to react to changes in telephony state, you can use the listen() method of TelephonyManager and implement a PhoneStateListener to receive changes in service, data connectivity, call state, signal strength, and other phone state information.

Working with Phone Numbers

Applications that deal with telephony, or even just contacts, frequently have to deal with the input, verification, and usage of phone numbers. The Android SDK includes a set of helpful utility functions that simplify handling of phone number strings. Applications can have phone numbers formatted based on the current locale setting. For example, the following code uses the formatNumber() method:

String formattedNumber =
    PhoneNumberUtils.formatNumber("9995551212");
Log.i("telephony", formattedNumber);

The resulting output to the log would be the string 999-555-1212 in my locale. Phone numbers can also be compared using a call to the PhoneNumberUtils.compare() method. An application can also check to see whether a given phone number is an emergency phone number by calling PhoneNumberUtils.isEmergencyNumber(), which enables your application to warn users before they call an emergency number. This method is useful when the source of the phone number data might be questionable


Image Tip

There are a number of utilities for formatting phone numbers based upon locale. Keep in mind that different countries format their numbers in different ways. For example, there is a utility method called formatJapaneseNumber() for formatting numbers with special prefixes in the Japanese style. To learn more about these utilities, see the PhoneNumberUtils documentation: http://d.android.com/reference/android/telephony/PhoneNumberUtils.html.


The formatNumber() method can also take an Editable as a parameter to format a number in place. The useful feature here is that you can assign the PhoneNumberFormattingTextWatcher object to watch a TextView (or EditText for user input) and format phone numbers as they are entered. The following code demonstrates the ease of configuring an EditText to format phone numbers that are entered:

EditText numberEntry = (EditText) findViewById(R.id.number_entry);
numberEntry.addTextChangedListener(
    new PhoneNumberFormattingTextWatcher());

While the user is typing in a valid phone number, the number is formatted in a way suitable for the current locale. Just the numbers for 19995551212 were entered on the EditText shown in Figure 14.1.

Image

Figure 14.1 Screen showing formatting results after entering only digits.

Using SMS

Integrating messaging services into an application can provide familiar social functionality to the user. SMS functionality is provided to applications through the android.telephony package and the recently introduced android.provider.Telephony package added in Android 4.4 KitKat (API Level 19). The Android 4.4 editions provide public SMS APIs, allowing developers to avoid the temptation of using undocumented SMS features in their applications, which is a practice that is greatly discouraged as there is no way to guarantee API compatibility with particular devices.

Default Messaging Application

Android 4.4 introduced a new way for users to select your application as their device’s default messaging application. This provides an opportunity for your application to remain front and center to your users whenever SMS and Multimedia Messaging Service (MMS) capabilities occur on their device. With that said, users are free to choose any messaging application as their default if other applications are also configured to become the default messaging application.

There are a few settings you need to declare in your application’s manifest file to remain eligible to become the default messaging application. These settings include:

Image An Activity: For other applications to send messages through the default SMS application, this Activity declaration requires including an <intent-filter> listing an <action> tag that names the SENDTO intent, and <data> tags for the sms, mms, smsto, and mmsto schema attributes.

Image An SMS BroadcastReceiver: For the default messaging application to receive incoming SMS, include the BROADCAST_SMS permission and an <intent-filter> with the SMS_DELIVER <action> tag name attribute.

Image An MMS BroadcastReceiver: For the default messaging application to receive incoming MMS, include the BROADCAST_WAP_PUSH permission, and an <intent-filter> with the WAP_PUSH_DELIVER <action> tag name attribute and a <data> tag with a mimeType of application/vnd.wap.mms-message.

Image A Service: For the default messaging application to respond to incoming phone calls with a quick response text message, include the SEND_RESPOND_VIA_MESSAGE permission, and an <intent-filter> with the RESPOND_VIA_MESSAGE <action> tag name attribute, and <data> tags for the sms, mms, smsto, and mmsto schema attributes.

With these settings configured in the application’s manifest, your application should show up in the device’s Default SMS app system settings list. Locate this by navigating to the device’s Settings application, and under Wireless & networks choose More . . ., then select Default SMS app to see your application listed in the settings. Figure 14.2 shows the Simple Telephony application listed in the Default SMS app list.

Image

Figure 14.2 Default SMS app settings list within the device settings.

If a user chooses not to make your application the default SMS app, you must include code to ensure that your application accounts for this, in case the user still wants to use your application for reasons other than being the default SMS application.

SMS Provider

A new SMS Provider has been included along with the default SMS application capabilities. This provider is only writable by the default SMS application, but readable by all applications other than the default SMS application. This provider includes tables for received messages, draft messages, pending messages, and sent messages, but only the default SMS application is able to mark messages as read and to delete messages, and it is responsible for writing its own messages to the provider database.

SMS Applications Other than the Default

In case your users do not choose your application to be the default SMS application, you may still use the android.telephony features for sending SMS simply by including the appropriate permissions and writing the appropriate code.

Gaining Permission to Send and Receive SMS Messages

SMS functionality requires two different permissions, depending on whether the application sends or receives messages. The following XML, to be placed in AndroidManifest.xml, shows the permissions needed for both actions:

<uses-permission
    android:name="android.permission.SEND_SMS" />
<uses-permission
    android:name="android.permission.RECEIVE_SMS" />

Sending an SMS

To send an SMS, an application first needs to get an instance of the SmsManager. Unlike other system services, this is achieved by calling the static method getDefault() of SmsManager:

final SmsManager sms = SmsManager.getDefault();

Now that the application has an SmsManager instance, sending SMS is as simple as a single call:

sms.sendTextMessage("9995551212", null, "Hello!", null, null);

We can create a simple form for sending an SMS message very easily. The code for the button handling looks like the following:

Button sendSMS = (Button) findViewById(R.id.send_sms);
sendSMS.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        String destination =
            numberEntry.getText().toString();

        String message =
            messageEntry.getText().toString();

        sms.sendTextMessage(destination, null, message,
            null, null);
    }
}

After this code is hooked in, the result should look something like Figure 14.3. In this application, we used the emulator “phone number” trick. This trick allows you to call another emulator instance by entering the port number of the emulator that you would like to call. This is a great way to test sending SMS messages without using hardware and without incurring charges by the handset operator.

Image

Figure 14.3 Two emulators, one sending an SMS from an application (left) and one receiving an SMS (right).

A great way to extend this is to set the sent receiver to modify a graphic on the screen until the sent notification is received. Further, you could use another graphic to indicate when the recipient has received the message. Alternatively, you can use ProgressBar widgets to track the progress to the user.

Making and Receiving Phone Calls

It might come as a surprise to the younger generation (they usually just text), but phones are often still used for making and receiving phone calls. Any application can be made to initiate calls and answer incoming calls; however, these abilities should be used judiciously so as not to unnecessarily disrupt the calling functionality of the user’s device.


Image Tip

You can also use two emulator instances to test calling to another handset. As with the SMS sending, the port number of the emulator is the phone number that can be called.


Making Phone Calls

You’ve seen how to find out if the handset is ringing. Now let’s look at how to enable your application to make phone calls as well.

Building on the previous example, which sent and received SMS messages, we now walk through similar functionality that adds a Call button to the screen to call the phone number instead of messaging it.

The Android SDK enables phone numbers to be passed to the dialer in two different ways. The first way is to launch the dialer with a phone number already entered. The user then needs to press the Send button to actually initiate the call. This method does not require any specific permissions. The second way is to actually place the call. This method requires the android.permission.CALL_PHONE permission to be added to the application’s AndroidManifest.xml file.

Let’s look at an example of how to enable an application to take input in the form of a phone number and launch the phone dialer after the user presses a button, as shown in Figure 14.4.

Image

Figure 14.4 The user can enter a phone number in the EditText control and press the Call button to initiate a phone call from within the application.

We extract the phone number the user entered in the EditText field (or the most recently received SMS when continuing with the previous example). The following code demonstrates how to launch the dialer after the user presses the Call button:

Button call = (Button) findViewById(R.id.call_button);
call.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        Uri number = Uri.parse("tel:" + numberEntry.getText().toString());
        Intent dial = new Intent(Intent.ACTION_DIAL, number);
        startActivity(dial);
    }
});

First, the phone number is requested from the EditText and tel: is prepended to it, making it a valid URI for the Intent. Then, a new Intent is created with Intent.ACTION_DIAL to launch into the dialer with the number dialed in already. You can also use Intent.ACTION_VIEW, which functions in the same way. Replacing it with Intent.ACTION_CALL, however, immediately calls the number entered. This is generally not recommended; otherwise, calls might be made by mistake. Finally, the startActivity() method is called to launch the dialer, as shown in Figure 14.5.

Image

Figure 14.5 One emulator calling (left) and the other receiving (right) after the Call button initiates the phone call from the calling application.

Receiving Phone Calls

Much as applications can receive and process incoming SMS messages, an application can register to answer incoming phone calls. To enable this in an application, you must implement a broadcast receiver to process intents with the action Intent.ACTION_ANSWER.

Remember, too, that if you’re not interested in the call itself but in information about the incoming call, you might want to consider using the CallLog.Calls content provider (android.provider.CallLog) instead. You can use the CallLog.Calls class to determine recent call information, such as:

Image Who called

Image When the person called

Image Whether it was an incoming or outgoing call

Image Whether or not anyone answered

Image The duration of the call

Working with SIP

Session Initiation Protocol (SIP) is a protocol for controlling communication sessions. SIP is at the same networking protocol level as HTTP or SMTP. The Android SDK addded support for SIP in API Level 9. The SIP APIs can be found in the android.net.sip package. Although the SIP APIs support generic sessions, the only type of session that is handled automatically is a Voice-over-Internet Protocol (VoIP) session.

Using SIP requires that you have an SIP account with an SIP service provider. Using SIP also requires the android.permission.USE_SIP permission to be set in your application’s Android manifest file. Additionally, for market filtering, the <uses-feature> tag should be set with android.software.sip and android.software.sip.voip features.

For more information about creating an application that uses SIP, including a fully working sample application that comes with the Android SDK, please see the links provided in the reference section at the end of this chapter.

What can you use SIP for? After all, aren’t most Android devices still phones? In-app voice communication can be useful. Perhaps your service provides a custom SIP server so that users can make voice connections with each other.

Summary

The Android SDK provides many helpful telephony utilities to handle making and receiving phone calls and SMS messages (with appropriate permissions) and tools to help with formatting phone numbers entered by the user or from other sources.

These telephony utilities enable applications to work seamlessly with the device’s core phone features. Developers might also integrate voice calls and messaging features into their own applications, resulting in compelling new features. Messaging is more popular than ever, so integrating text messaging into an application can add a familiar and exciting social feature that users will likely enjoy.

Quiz Questions

1. What application permission is needed to access basic phone state information?

2. How would you retrieve an instance of TelephonyManager within your application?

3. True or false: The getVoiceState() method is used to determine the voice call status of a handset.

4. What are the four declarations you must make in your manifest file so your application is eligible for the default SMS app?

5. True or false: All SMS applications are capable of writing directly to the SMS Provider.

Exercises

1. Use the Android documentation to determine the class used for providing information about the signal strength of a phone.

2. Use the Android documentation to determine the Telephony.SMS class that provides information about outgoing messages.

3. Create an application that may operate as the default SMS application if a user selects it as the default SMS application and that may operate as an SMS application if a user selects another application as the default SMS application.

References and More Information

3GPP specifications (SMS):

http://www.3gpp.org/specifications

Wikipedia’s write-up on SMS:

http://en.wikipedia.org/wiki/SMS

Android SDK Reference documentation on the android.telephony package:

http://d.android.com/reference/android/telephony/package-summary.html

Android SDK Reference documentation on the Telephony class:

http://d.android.com/reference/android/provider/Telephony.html

Android Developers Blog: “Getting Your SMS Apps Ready for KitKat”:

http://android-developers.blogspot.com/2013/10/getting-your-sms-apps-ready-for-kitkat.html

Android API Guides: “Session Initiation Protocol”:

http://d.android.com/guide/topics/connectivity/sip.html

Android SDK Reference documentation on the android.net.sip package:

http://d.android.com/reference/android/net/sip/package-summary.html

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.90.140