13. Using Android Telephony APIs

Although the Android platform has been designed to run on almost any type of device, the Android devices available on the market are primarily phones. Applications can take advantage of this fact by integrating phone features into their feature set.

Generally speaking, developers should consider an Android device first and foremost as a phone. Although these devices might also run applications, phone operations generally take precedence. 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.

Phones typically support a Short Message Service (SMS), which is popular. 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.

Finally, because it is a phone, applications that deal with phone numbers, such as a contacts database or yellow pages application, can directly access the phone dialer. This enables a more integrated user experience and enhances the overall value of the application to the users.

This chapter introduces you to various telephony-related APIs found within the Android SDK.

Working with Telephony Utilities

The Android SDK provides a number of useful utilities for applications to integrate phone features available on the device.

Among these are the ability to request the hook state of the phone, information of the phone service, and utilities for handling and verifying phone numbers. The TelephonyManager object within the android.telephony package is a great place to start.

Gaining Permission to Access Phone State Information

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. We talk more about Location-Based Services in Chapter 11, “Using Location-Based Services (LBS) APIs.”

The following block of XML is typically needed in your 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.

An instance of TelephonyManager can be requested using the getSystemService() method.

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:

image


The three call states can be simulated with the emulator through the Dalvik Debug Monitor Service (DDMS) tool, which is discussed in detail in Appendix B, “The Android DDMS Quick-Start Guide.”

Querying for the call state can be useful in certain circumstances. However, listening for changes in the call state can allow 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 users can safely answer it. An application can register to listen for changes in the call state by making a call to the listen() method of TelephonyManager.

image


The listener will be 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 state of the phone is determining the state of the service. This information can tell an application if the phone has coverage at all, if it can only make emergency calls, 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 above 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.

image


In addition, 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, other information about the device can be retrieved. This information is less useful for the typical application but can diagnose problems or provide specialized services available only when on certain provider networks. The following code retrieves several pieces of service information.

image


The network operator name is the descriptive name of the current provider that the handset connects to. This is typically the current tower operator. The SIM operator name is typically the name of the provider that the user is subscribed to for service. The phone number for this application programming interface (API) is defined as the MSIDN, typically the directory number of a GSM handset—the number someone would dial to reach it.

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 numbers strings. Applications can have phone numbers formatted based on the current locale setting. For example, the following code uses the formatNumber() method:

image


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 if a given phone number is an emergency phone number by calling PhoneNumberUtils.isEmergencyNumber(). Checking this can be used to warn a user before they call an emergency number. This method is useful when the source of the phone number data might be questionable. In SDK Version 1.5, a new utility method called formatJapaneseNumber() was added for formatting numbers with special prefixes in the Japanese style.

The formatNumber() method can also take an Editable as a parameter to format a number in place. The useful feature here is that the PhoneNumberFormattingTextWatcher object can be assigned 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:

image


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

Figure 13.1. Screen showing formatting results after entering only digits.

image

Using SMS

SMS usage has become ubiquitous in the last several years. Integrating messaging services, even if only outbound, to an application can provide familiar social functionality to the user. SMS functionality is provided to applications through the android.-telephony.gsm package.

Caution

The current version of the Android SDK uses the android.telephony.gsm package. If Android runs on a device that is something other than a GSM device, this package might not work.

Gaining Permission to Send and Receive SMS Messages

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

image


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 the SmsManager, sending SMS is as simple as a single call.

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


The application will not know if the actual sending of the SMS was successful or not without providing a PendingIntent to receive the broadcast of this information. The following code demonstrates configuring a PendingIntent to listen for the status of the SMS:

image


The PendingIntent pendingMsgSent can be used with the call to the sendTextMessage(). The code for the message-received receipt is similar but is called when the sending handset receives acknowledgment back from the network that the destination handset received the message.

If we put all this together with the preceding phone number formatting EditText, a new entry field for the message, and a button, we can create a simple form for sending an SMS message. The code for the button handling will look like the following:

image


After this code is hooked in, the result should look something like Figure 13.2. Within this application we used the emulator “phone number” trick (its port number). This is a great way to test sending SMS messages without using hardware or without incurring charges by the handset operator.

Figure 13.2. Two emulators, one sending an SMS from an application and one receiving an SMS.

image

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

Receiving an SMS

Applications can also receive SMS messages. To do so, your application must register a BroadcastReceiver to listen for the Intent action associated with receiving an SMS. An application listening to SMS in this way doesn’t prevent the message from getting to other applications.

Expanding on the previous example, the following code shows how any incoming text message can be placed within a TextView on the screen.

image


This block of code is placed within the onCreate() method of the Activity. First, the message Bundle is retrieved. In it, an array of Objects holds several byte arrays that contain PDU data—the data format that is customarily used by wireless messaging protocols. Luckily, the Android SDK can decode these with a call to the static SmsMessage.createFromPdu() utility method. From here, we can retrieve the body of the SMS message by calling getDisplayMessageBody().

The message that comes in might be longer than the limitations for an SMS. If it is, it will have been broken up in to a multipart message on the sending side. To handle this, we loop through each of the received Object parts and take the corresponding body from each while only taking the sender address from the first.

Tip

When dealing with multipart text messages, it’s important to know that the user might be charged the full texting charge for each part of the message. This can add up quickly. Care should be taken to warn users that applications that use any text messaging, sending or receiving, might incur charges by their operator.

An application can send a similar multipart message by taking advantage of the SmsManager.divideMessage() method. This method breaks up a String into parts no larger than the maximum size allowed by the SMS specification. The application could then use the method called sendMultipartTextMessage(), passing in the result of the call to divideMessage().

Next, the code updates the text string in the TextView to show the user the received message, as shown in Figure 13.3. The sender address is also updated so that the recipient can respond with less typing.

Figure 13.3. The application shows the message at the bottom and places the sender number in the phone number field.

image

Finally, we register the BroadcastReceiver with the system. The IntentFilter used here, android.provider.Telephony.SMS, is a well-known, but undocumented, IntentFilter used for this. As such, we have to use the string literal for it.

Caution

We strongly recommend watching for updates to the Android SDK in relation to this functionality. Future versions of the SDK might either add this string officially or remove the feature entirely.

Making Phone Calls

It might come as a surprise to the younger generation, but phones are often still used for making phone calls. You’ve seen how to find out if the handset is ringing. Now you learn how your application can make a phone call.

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.

Caution

Although the android.permission.CALL_PHONE permission is required for immediately calling a number when using the T-Mobile G1 handset, this permission is not enforced on the emulator as of this writing. Remember to test on actual devices to verify correct behavior.

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

image


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 in to the dialer with the number dialed in already. Intent.ACTION_VIEW can also be used and functions the same. 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 13.4.

Figure 13.4. One emulator calling the other after pressing the Call button within the application.

image

Tip

Two emulator instances can also be used 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.

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.

References and More Information

3GPP Specifications (SMS): /www.3gpp.org/specifications

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

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

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