The previous chapter showed how to use Android’s built-in PhoneApp application, which simplifies the task of placing of phone calls. This chapter shows you how to get more information about telephone service and the actual calls you make.
After an example that puts one of the telephony features to use, we’ll present a short guide to PhoneApp internals.
We use the term “telephony” to refer to the parts of the Android system that depend on a radio communicating with the public land mobile network (PLMN) to provide communication and location functions. Sharing the use of this radio among multiple applications is a key goal for Android’s telephony modules.
The android.telephony
package contains a set of classes that can be used by any
application in the Android environment to monitor the state of
Android’s mobile network connection. It also contains classes for
locating a device using the mobile network. Finally, it offers utility
classes for parsing, formatting, and otherwise managing phone numbers,
although there is no architectural benefit to locating those classes
in this package.
The telephony package does not allow you to place, end, or otherwise meddle in phone calls; it focuses on retrieving information and giving users an interface to edit telephone numbers. We’ll explain later why Android reserves the actual control over phone calls to PhoneApp.
The android.telephony
package contains the following packages:
CellLocation
PhoneNumberFormattingTextWatcher
Callback methods that notify an application about
changes to phone numbers themselves. When used with a TextView
object, it formats the text
as a phone number using methods in the PhoneNumberUtils
class.
PhoneNumberUtils
A utility class that contains methods for processing strings containing phone numbers.
PhoneStateListener
Callback methods that track changes in the state of the mobile network connection, the call, or other telephony objects.
ServiceState
Methods that return information about the current mobile network service provider and the availability of service.
TelephonyManager
Methods that provide information about the state of mobile service, the call state, the SIM, the network, the subscriber to the mobile service, voicemail, and other related information.
Because these classes don’t control hardware or change state information about phone calls, they don’t have any access control.
Some readers may be disappointed to see that the android.telephony
package limits their
access to getting information, and does not provide direct control
over the dialer or the state of a call. There are good reasons for
this. Essentially, providing a low-level telephony API that can be
shared among multiple applications is perilous.
A mobile handset is a state machine that keeps track of the mobile radio reports, provides audible call state indications to the user, and enables the user to provide inputs that modify that state. Even if you could design an API that would, hypothetically, share a mobile radio among multiple applications on a per-call basis, the user interface and ergonomic design that would go along with shared control among multiple applications would be difficult and probably even intractable. A phone is not like a PC with a desktop user interface: you can’t share control over the parts of a device that constitute the phone the way you can share the screen of a PC.
Android provides a workable solution that keeps telephony
usable while making as much of the system open to your applications
as is practicable. As we saw in the previous chapter, PhoneApp exposes an
Intent that lets other applications initiate phone calls, while
enabling a single application to control the mobile radio in an
Android handset. The android.telephony
package further exposes
information about telephone service and the calls made by an
application.
It’s useful to think of telephony on Android as an interface that keeps critical functions private while providing public APIs for functions where it is safe to do so. This is a good example of a successful Android design strategy.
This section shows how to track the state of a phone call. It adds some of the classes described in the previous section to the application shown in Creating an Example Application to Run the call Method, which finds and uses PhoneApp to start and control a phone call. Here, in addition to starting a phone call and letting PhoneApp control it, the application gets some information about the call as it is happening.
In order to get this information, we need to extend the
PhoneStateListener
class, make an
instance of our subclass, and pass that instance to the TelephonyManager.listen
method. Example 15-1 shows the code for our
subclass of the PhoneStateListener
class.
private class ListenToPhoneState extends PhoneStateListener { public void onCallStateChanged(int state, String incomingNumber) { Log.i("telephony-example", "State changed: " + stateName(state)); } String stateName(int state) { switch (state) { case TelephonyManager.CALL_STATE_IDLE: return "Idle"; case TelephonyManager.CALL_STATE_OFFHOOK: return "Off hook"; case TelephonyManager.CALL_STATE_RINGING: return "Ringing"; } return Integer.toString(state); } }
The lines we’ve highlighted are:
In this subclass of the PhoneStateListener
class, we override the
onCallStateChanged
method, which
Android calls when a call’s state changes. We use the Log
class, a static class with utility
methods for logging information, to log the changes as Android
passes them to us.
Finally, our stateName
method decodes the states that correspond to the constants defined
in the TelephonyManager
class to
make the log more readable.
Returning to our main application from Creating an Example Application to Run the call
Method, we have to change
it by creating a Listener and assigning our subclass of PhoneStateListener
to it. Here is the code
for the entire modified example application, which now tracks and
logs state transitions:
package example.telephony; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; public class telephonyExplorer extends Activity { ListenToPhoneState listener; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); call(); } private void call() { try { Intent callIntent = new Intent(Intent.ACTION_CALL); callIntent.setData(Uri.parse("tel:9785551212")); startActivity(callIntent); TelephonyManager tManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); listener = new ListenToPhoneState(); tManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); } catch (ActivityNotFoundException activityException) { Log.e("telephony-example", "Call failed", activityException); } } private class ListenToPhoneState extends PhoneStateListener { public void onCallStateChanged(int state, String incomingNumber) { Log.i("telephony-example", "State changed: " + stateName(state)); } String stateName(int state) { switch (state) { case TelephonyManager.CALL_STATE_IDLE: return "Idle"; case TelephonyManager.CALL_STATE_OFFHOOK: return "Off hook"; case TelephonyManager.CALL_STATE_RINGING: return "Ringing"; } return Integer.toString(state); } } }
The lines we’ve highlighted are:
New classes that must be imported to add a Listener for the telephone call state.
Adds a definition for the Listener.
Connects to Android’s telephone call manager.
Assigns our extended Listener
class (defined at item 5) to
the variable defined in item 2.
Code from Example 15-1, defining our Listener.
Running this application results in output to the log window in Eclipse that should look something like this:
11-19 01:47:03.704: INFO/telephony-example(159): State changed: Idle 11-19 01:47:04.774: INFO/telephony-example(159): State changed: Off hook
The rest of this chapter covers telephony-related classes
in the internals package that only PhoneApp uses, android.internal.telephony
. This package is
layered over an implementation of telephony internals for a particular
telephony technology, such as GSM or CDMA. That layer, in turn,
communicates with a Radio Interface Layer (RIL) that is implemented as a daemon in Android.
Figure 15-1 shows the architecture of the Android telephony system. PhoneApp supports an Intent that enables other applications to start phone calls. The Telephony Manager is available through Listeners, as shown in the previous section.
Many of the internal packages use the remote methods
feature discussed in Remote Methods and AIDL. The TelephonyManager
and PhoneStateListener
classes rely on this to
communicate with PhoneApp. The ServiceManager
class is also used.
To marshall data for remote methods, the package includes AIDL files. For instance, the following AIDL comes from IPhoneStateListener.aidl:
oneway interface IPhoneStateListener { void onServiceStateChanged(in ServiceState serviceState); void onSignalStrengthChanged(int asu); void onMessageWaitingIndicatorChanged(boolean mwi); void onCallForwardingIndicatorChanged(boolean cfi); // we use bundle here instead of CellLocation so it can get the right subclass void onCellLocationChanged(in Bundle location); void onCallStateChanged(int state, String incomingNumber); void onDataConnectionStateChanged(int state); void onDataActivity(int direction); }
This package contains the classes and interfaces PhoneApp uses to provide services to other applications that want to start phone calls, and classes that define an API to the RIL.
PhoneApp, like all parts of Android, is theoretically replaceable. If your application needs to modify the classes used by PhoneApp, your application will probably have to replace or modify PhoneApp, and should provide the same services to other applications, using the classes in this package.
The description of these classes should help you understand how Android interfaces to a mobile radio, and the capabilities that are exposed—and not exposed—by PhoneApp to other applications. This is a large and complex package, and a complete understanding will require reading the Android source code. These descriptions will help you find where to start for your purposes:
ATParseEx
Extends RuntimeException and is thrown by methods of
the ATResponseParser
class.
ATResponseParser
This class parses part of the AT command syntax used to communicate with the mobile radio hardware in a mobile handset. This is, in fact, a command syntax very much like the AT command syntax used by modems, a standard described in the 3GPP document number TS 27.007 and related specifications. This protocol for controlling mobile radios is widely used.
Call
This class is an abstract base class. Other classes use it as a basis for objects that represent phone calls and the state of those calls.
CallerInfo
This class holds information about the party that originated an incoming call. This class starts with caller ID information from the mobile network interface and looks up other information about a caller in the database of contacts.
CallerInfoAsyncQuery
This class enables asynchronous database queries for information that could be found about a caller based on the caller ID information.
CallStateException
The class extends Exception and is thrown by methods that maintain call state in cases where state is inconsistent.
Connection
This class is an abstract base class used by other
classes, and is a basis for objects that represent connections
on the mobile network and the state of these connections.
Connection
objects can be
associated with a Call
object, but they can also exist independently. The data in a
Connection
object can be
especially useful in diagnosing the reason a call
failed.
DefaultPhoneNotifier
This class implements the PhoneNotifier interface in order
to receive notifications from a Phone
object. It then uses the
Android service system to communicate state to Activity
instances that have registered to receive those notifications.
See the Handler
and
Mailbox
classes for
information on how to receive notifications.
IPhoneStateListener
This interface defines the signatures of methods an application implements to receive notification of call state change, and changes to forwarding and message-waiting states.
IPhoneSubInfo
ITelephony
This interface defines the inter-process interface used in TelephonyManager to enable applications to communicate with PhoneApp.
ITelephonyRegistry
This interface is the callback interface from the RIL daemon.
MmiCode
This interface defines callbacks related to “MMI codes.” These are special numbers a user can dial and key sequences that a user can enter during a call to access, control, and administer supplementary services, such as call waiting, call hold, etc. MMI codes and related functionality are described in the 3GPP document number TS 22.030.
Phone
This interface includes callbacks and methods for accessing the state of a mobile phone.
PhoneBase
This class is an abstract base class that implements the Phone interface.
PhoneFactory
This class contains methods used to create instances
of the GSMPhone
class, a
subclass of the Phone
class.
PhoneNotifier
This interface specifies the API a telephony implementation uses to notify a phone state listener of state changes.
PhoneStateIntentReceiver
This class handles Intent
objects that have intent
types specified in the TelephonyIntents
class. This
class enables Android applications to use the Intents system
to obtain phone state information.
PhoneSubInfo
This class contains methods for obtaining information about a mobile service subscriber, such as the unique identifying number for the handset (IMEI), the unique identifying number for the subscriber (IMSI), the serial number of the SIM card, etc.
SimCard
TelephonyIntents
This class defines constants for broadcast intents that have similar functionality to the TelephonyManager API.
TelephonyProperties
This class defines the constants used with the SystemProperties
class for setting
and getting telephony-related properties.
These classes are not documented in the Android SDK documentation, but the descriptions here should give you some understanding of the source code for these classes.
Many of the classes and interfaces in the previous section are
typical of a Java API that can have multiple implementations. The
implementations of the API defined in the telephony.internal
package correspond to a
library used in the RIL. To better understand this API, we will look
at one implementation here that supports GSM.
Thus, this section delves further into the telephony internals of Android, looking especially at how the interfaces and abstract base classes are implemented and subclassed to enable access to the functionality of GSM telephony. Although it may seem that specifications such as TS 27.007 cover mobile telephony in general, this layer of Android actually has to accommodate variations in mobile telephony standards. In CDMA telephony, for instance, the SIM card is an optional part of the standard and is rarely present in CDMA handsets. In this case, the package described in this section would be replaced by a CDMA-oriented package with a similar architectural relationship to the higher-level classes described in the previous section. The RIL code is also specific to the type of telephony in the handset.
At the RIL layer, the differences between GSM and CDMA are mainly outside the core functionality of making phone calls, so you may be wondering why all these layers and APIs are necessary. But, as the description of the classes specific to communicating with a GSM RIL will show, there are plenty of differences in detail, such as SIM cards, the type of mobile data network, etc. These make it impractical to design a universal interface to mobile radios, despite the use of a standard protocol for communicating with them:
AdnRecord
This class is used to load and store Abbreviated Dialing Numbers (ADNs) to and from the SIM card. ADNs are short numbers used for information calls, emergency calls, etc.
AdnRecordCache
ApnSetting
This class holds data specifying the access point name (APN) and other parameters for connecting to General Packet Radio Service (GPRS) and 3G mobile data networks. This mobile data technology is specific to GSM networks.
BaseCommands
This class implements the CommandsInterface interface,
which is used throughout the GSM
telephony classes to communicate
with the GSM radio.
CallFailCause
This interface defines constants for decoding failure cause codes.
CallForwardInfo
This class holds data that corresponds to the parameters of a call-forwarding command to the RIL.
CallTracker
This class maps information from the RIL to state
transitions for the GSMCall
class.
CommandException
This class is an exception thrown when the RIL reports an error from a command.
CommandsInterface
This interface defines the API to the GSM RIL. This interface
is implemented by the BaseCommands
class.
DataConnectionTracker
This tracks the state of GPRS packet data protocol (PDP) connections. This type of connection is specific to GSM mobile data.
DataLink
This class implements the DataLinkInterface interface and
is used in the PPPLink
class, which manages point to point protocol (PPP) links in
GPRS networking.
DataLinkInterface
This class defines the API for connecting and disconnecting PPP links.
DriverCall
This class parses information, in AT command syntax, from the mobile radio, and turns it into call state information.
EncodeException
This class is an exception thrown by methods of the GSM
alphabet class, which encodes
UTF-16 (as used in Java) into the 7-bit SMS character
set.
GSMAlphabet
This class is a utility class containing static methods for encoding UTF-16 to the 7-bit SMS character set.
GSMCall
This class extends the Call
class, and implements the
abstract methods of that class, thereby implementing parts of
the Android telephony internals API. This class models calls
in GSM telephony.
GSMConnection
This class extends the Connection
class, and like the
GSMCall
class, implements
the abstract methods of the Connection
class. This class models
connections in GSM telephony.
GSMPhone
This class extends the Phone
class and, as with both the
GSMCall
and GSMConnection
classes,
implements the abstract methods of the Phone
class.
GsmMmiCode
This class implements the MmiCode interface and the part of the telephony API defined in that interface.
GsmSimCard
This class implements the SimCard interface, another part of the implementation of the telephony internals API. This class enables access to data in the SIM card.
ISimPhoneBook
This interface defines an API for accessing ADN records stored in the SIM card.
ISms
MccTable
This class is a utility class that contains a table of Mobile Country Codes (MCCs). In principle, these codes are not specific to a GSM RIL, but they are specific to this implementation of a GSM RIL.
NetworkInfo
PDPContextState
This contains data about a PDP session, including the IP address.
PdpConnection
This class contains information about the data connection associated with a PDP context.
PppLink
This class extends DataLink and implements DataLinkInterface to provide an implementation of this part of the RIL interface.
RIL
This class extends the BaseCommands
class and also
implements the CommandsInterface interface,
forming a complete implementation of the interface for sending
commands to the RIL. This is where communication with the RIL
takes place. An instance of the RIL
class is created in the PhoneFactory
class, in the course of
creating an instance of the GSMPhone
class.
RILConstants
ServiceStateTracker
This class polls the RIL daemon for signal strength and tracks other aspects of the state of mobile service.
SIMFileHandler
SIMRecords
This class enables access to specific files in the SIM filesystem containing information such as the subscriber’s IMSI.
SimConstants
This interface contains constants used in other classes accessing data in the SIM.
SimException
This class extends Exception and is used in other classes to throw an exception related to errors accessing data in the SIM.
SimFileNotFound
This class extends SimException
and is used in the SimIoResult
class in specific error
conditions.
SimPhoneBookInterfaceManager
This class extends ISimPhoneBook
and provides a service interface for accessing
ADN records in the SIM.
SimProvider
This class extends ContentProvider
and creates a
content provider interface to SIM ADN/SDN/FDN records in the
SIM.
SimSmsInterfaceManager
This class extends ISms and creates a service interface for accessing SMS messages stored in the SIM.
SimTlv
This class is an object interface for accessing
tag-length-value records in the SIM, and is used in the
SIMRecords
class.
SimUtils
This class contains static utility methods for manipulating data encoded in binary-coded decimal and other encodings encountered in SIM data.
SMSDispatcher
This class implements the sending of SMS messages and notifies applications that use the Handler interface to this class regarding the status of SMS messages.
SmsHeader
This class contains constants and methods for decoding SMS headers.
SmsRawData
This class implements Parcelable and is used in implementing service interfaces for accessing SIM data.
SmsResponse
This class associates a message reference with an acknowledgment.
SuppServiceNotification
This class contains constants for decoding information about supplementary services.
VoiceMailConstants
This class parses information in the etc/voicemail-conf.xml file.
There is another package organized hierarchically under the
internal.telephony.gsm
package:
the stk
package, which contains
classes for accessing the SIM. This package is not exposed outside
the internal.telephony.gsm
package and is beyond the scope of this chapter.
A lot of code lies between creating an ACTION_CALL
Intent
object and dialing a call. Here we will go even deeper into
Android’s telephony system to see what Android is telling the mobile
radio, and match that up with what we have done in the example
application earlier in this chapter.
To see how, and when, Android actually commands the hardware
to dial a number, we can use Android’s logging system. To access the
log buffer for information about the traffic between Android
software and the mobile radio, we will also have to use the Android
Debug Bridge, adb
. We will
start a shell that can run commands in the emulator, and we will use
the logcat utility to display logging information as it becomes
available.
First, set a breakpoint in the example application on line 25,
where the Intent
object is
created and before the call to the startActivity
method.
Then, start the application with the debugger: Select Run → Debug. When the “Debug as” dialog appears, select Android Application.
The application will run and stop at the breakpoint.
Now look at the log. Open a command-line window and change your working directory to the directory where you have put the Android SDK. There you should see a directory named tools. Change your working directory to tools. You should see a program there named adb.
Next, use adb
to find
the name of the emulator that is running as a result of starting the
application with the debugger. Type the following:
./adb devices
adb
will list all the
emulators running, which should be just one. The output will look
something like this:
... emulator-5554 device
Now use adb
to start a
shell that can run programs in the emulator (if adb
finds an emulator with a different name on
your system, use that name instead of “emulator-5554”):
./adb
-s emulator-5554 shell
This will result in a shell prompt:
#
The shell you are now typing commands into is executing those
commands in the emulator. Now use the logcat
command to show the log of
traffic between the mobile radio and the RIL:
# logcat
-b radio
This will result in a lengthy listing of AT commands and responses. For the most part, they are asking for and reporting the signal strength. This is what the RIL and the mobile radio are doing when nothing else is going on.
The lines tagged D/AT
are
the verbatim AT commands exchanged between the mobile radio and the
RIL. The ones labeled AT>
are
from the RIL to the mobile radio, and the ones labeled AT<
are from the mobile radio to the
RIL. The other lines in the log are a more-readable decoding of the
information in the AT commands. You can see the part of the RIL
interface in Java logging requests sent to the RIL daemon, RILD, and
the RIL code in RILD logging as it sends the appropriate AT commands
to the mobile radio and decodes the results.
Now use the Eclipse debugger to step over the line where the
Intent
object is created. Looking
at the log output, you see that nothing interesting has happened
yet: the RIL and the mobile radio (really, an emulation of a mobile
radio) are polling the signal strength. Step over the next line,
where the phone number is added to the Intent
object and, similarly, nothing has
happened yet.
Now step over the next line, which should look like this:
startActivity(callIntent);
Here we get quite a bit of interesting output from the logger. It should look something like this:
D/GSM ( 85): [GSMConn] update: parent=DIALING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true,changed=false D/RILJ ( 85): [0161]> SET_MUTE false D/RIL ( 22): onRequest: SET_MUTE D/RILJ ( 85): [0161]< SET_MUTE error: com.android.internal.telephony.gsm.CommandException: REQUEST_NOT_SUPPORTED D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0162]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< +CLCC: 1,0,2,0,0,"9785551212",129 D/AT ( 22): AT< OK D/RILJ ( 85): [0162]< GET_CURRENT_CALLS [id=1,mo,DIALING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=DIALING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=false D/AT ( 22): AT< RING D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0163]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< +CLCC: 1,0,3,0,0,"9785551212",129 D/AT ( 22): AT< OK D/RILJ ( 85): [0163]< GET_CURRENT_CALLS [id=1,mo,ALERTING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ALERTING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=true D/RILJ ( 85): [0164]> SET_MUTE false D/RIL ( 22): onRequest: SET_MUTE D/RILJ ( 85): [0164]< SET_MUTE error: com.android.internal.telephony.gsm.CommandException: REQUEST_NOT_SUPPORTED D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0165]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< +CLCC: 1,0,3,0,0,"9785551212",129 D/AT ( 22): AT< OK D/RILJ ( 85): [0165]< GET_CURRENT_CALLS [id=1,mo,ALERTING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ALERTING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=false D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0166]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< +CLCC: 1,0,3,0,0,"9785551212",129 D/AT ( 22): AT< OK D/RILJ ( 85): [0166]< GET_CURRENT_CALLS [id=1,mo,ALERTING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ALERTING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=false D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0167]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< RING D/AT ( 22): AT< +CLCC: 1,0,0,0,0,"9785551212",129 D/AT ( 22): AT< OK D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0167]< GET_CURRENT_CALLS [id=1,mo,ACTIVE,voice,norm,129,0] D/RILJ ( 85): [0168]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< +CLCC: 1,0,0,0,0,"9785551212",129 D/AT ( 22): AT< OK D/RILJ ( 85): [0168]< GET_CURRENT_CALLS [id=1,mo,ACTIVE,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ACTIVE, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=false, changed=true D/GSM ( 85): [GSMConn] onConnectedInOrOut: connectTime=1225978001674 D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0169]> SET_MUTE false D/RIL ( 22): onRequest: SET_MUTE D/RILJ ( 85): [0169]< SET_MUTE error: com.android.internal.telephony.gsm.CommandException: REQUEST_NOT_SUPPORTED D/RILJ ( 85): [0170]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< +CLCC: 1,0,0,0,0,"9785551212",129 D/AT ( 22): AT< OK D/RILJ ( 85): [0170]< GET_CURRENT_CALLS [id=1,mo,ACTIVE,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ACTIVE, hasNewParent=false, wasConnectingInOrOut=false, wasHolding=false, isConnectingInOrOut=false, changed=false
What you are seeing here is a mobile call being started. The call goes through three states: “dialing,” “alerting,” and “active.” Take a look at how the mobile radio reports the state of a call. Here the call is in the “dialing” state:
+CLCC: 1,0,2,0,0,"9785551212",129
Here the call is in the “alerting” state:
+CLCC: 1,0,3,0,0,"9785551212",129
Here the call is in the “active” state:
+CLCC: 1,0,0,0,0,"9785551212",129
The third number in the list of parameters in the AT command response indicates the state of this call. The classes that model the connection, call, and network state in PhoneApp and the TelephonyManager API keep track of what RILD is telling the mobile radio and what the mobile radio is telling RILD, and this is where that information comes from.
Now press the red End button (the one with the picture of a
telephone receiver) to end the call. Look for the AT commands that
read the state change from the mobile radio, and at the
corresponding TelephonyManager
method call that notifies the application of the change.
You may have come to the end of this description of Android telephony surprised, and perhaps disappointed, to find no mention of Voice over IP (VoIP). After all, GoogleTalk supports voice calls from PC to PC. Why was this capability omitted from the core telephony functionality of Android?
Android was not designed to treat VoIP calls and mobile calls similarly or, from a programmer’s perspective, through the same APIs. What you see described in this chapter is an abstraction for mobile telephony, not telephony in general. AT commands that are nearly universal in mobile telephony—and that are not used outside mobile telephony—pervade the APIs described here all the way up to the PhoneApp application. The inter-process interfaces are designed around capabilities of mobile telephony, mobile messaging, and mobile data.
As a result, designers of VoIP technologies for Android are left
with some design decisions. The current direction treats VoIP as a
separate application and makes it possible in the future to provide a
very high-level integration with other parts of the system—for
example, supporting the ACTION_CALL
call in Intent
objects.
This development would give the user a choice between Android’s
built-in mobile telephony and an add-on for VoIP telephony.
A deeper integration of mobile telephony and VoIP can be implemented in Android, but it would require extending the functionality of PhoneApp to encompass both IP and conventional mobile telephony, while providing a compatible interface to applications written to Android’s TelephonyManager API.
35.171.45.182