Android Phone Status Sample






4.78/5 (34 votes)
A Simple android application to display the phone details, battery status and data connectivity status of an Android Smartphone
Introduction
This article shall make use of API’s inside android.telephony and android.os.batterymanager packages present in the Android SDK to create a simple yet smart application to display the phone details, battery status and data connectivity status of an Android Smartphone.
Background
The Android framework gives you everything you need to build best-in-class app experiences. The core component of this is the Android Software Development Kit (Android SDK) that provides all necessary tools to build, test and deploy an application. In this article we mainly focus on the following packages / classes to display some of the very common information related to a cellular phone.
Service Provider Related
- Service state
- Cell Location
- Call State
- Connection State
- Signal Strength
- Data Exchange.
Phone Specific
- Device ID
- Phone number
- SW Version
- Operator Name
- SIM Country Code
- SIM Operator
- SIM Serial No
- Subscriber ID
- Network type
- Phone type
- Battery Related Information
In order to retrieve the above mentioned information from the Android system, we have to include the permissions in our android application in the AndroidManifest.xml file. The below mentioned list presents the user with appropriate permissions that are required to be included in AndroidManifest.xml file for a certain information request.
Permissions in Android manifest
No | Information | Permission |
1 | Cell location | ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION |
2 | Call State | |
3 | Data Connection State | |
4 | Signal Strength | |
5 | Data Direction States | |
6 | Service State | |
7 | Device ID | READ_PHONE_STATE |
8 | Phone Number | READ_PHONE_STATE |
9 | Operator Name | READ_PHONE_STATE |
10 | SIM Operator | READ_PHONE_STATE |
11 | SIM Country Code | READ_PHONE_STATE |
12 | SIM Serial No. | READ_PHONE_STATE |
13 | Subscriber ID | READ_PHONE_STATE |
14 | Network Type | ACCESS_NETWORK_STATE |
Phone Type |
Designing the Android application layout
The next step is to design a layout file which shall display the information that we are interested in. For the sake of clarity i have included a tabbed layout in this sample. The first tab shall display the telephony related information while the second tab shall show the current battery status of the phone.
The main.xml
This layout shall host a tab widget. Depending on the selection shall display the Phone Status or Battery Status information
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@android:id/tabhost">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</TabWidget>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
</LinearLayout>
</TabHost>
phonestatus.xml
This layout shall display the telephony related information such as Call State,Cell location, Connection state, Signal level, Data activity, Phone number , IMEI code , Device SW version and so on.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:scrollbarStyle="insideOverlay"
android:scrollbarAlwaysDrawVerticalTrack="false">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!--Service State-->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:text="@string/tvServiceState" style="@style/labelStyleRight"/>
<TextView android:id="@+id/serviceState_info" style="@style/textStyle"/>
</LinearLayout>
<!--cell location -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:text="@string/tvCellLocation" style="@style/labelStyleRight"/>
<TextView android:id="@+id/cellLocation_info" style="@style/textStyle"/>
</LinearLayout>
<!--Call State-->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:text="@string/tvCallState" style="@style/labelStyleRight"/>
<TextView android:id="@+id/callState_info" style="@style/textStyle"/>
</LinearLayout>
<!--Data Connection State-->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:text="@string/tvConnState" style="@style/labelStyleRight"/>
<TextView android:id="@+id/connectionState_info" style="@style/textStyle"/>
</LinearLayout>
<!--Signal level -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:text="@string/tvSignalLevel" style="@style/labelStyleRight"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:orientation="horizontal">
<ProgressBar android:id="@+id/signalLevel" style="@style/progressStyle"/>
<TextView android:id="@+id/signalLevelInfo" style="@style/textSmallStyle"/>
</LinearLayout>
</LinearLayout>
<!--Data Activity-->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:text="@string/strData" style="@style/labelStyleRight"/>
<ImageView android:id="@+id/dataDirection" style="@style/imageStyle"/>
</LinearLayout>
<TextView android:id="@+id/device_info" style="@style/labelStyleLeft"/>
</LinearLayout>
</ScrollView>
Once the data has been assigned inside the PhoneStatusActivity (described later). The layout file would produce a screen as below
The battery.xml
The layout shall serve as a placeholder to display the phone battery specific information. The layout file consists of a simple textview. The data source for this text view shall be set inside BatteryStatusActivity.java (described later)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:id="@+id/batterylevel" style="@style/textStyleCenter"/>
</LinearLayout>
The layout file shall output to something similar as shown below
Android Layout Styles
Styles in Android is analogous to cascading stylesheets (CSS) in web
design i.e they allow you to separate the design from the
content. For a consistent look and feel in the Battery Status and Phone Status layout we will include a styles.xml file inside the res/values folder which will specify properties such as height, padding, font color, font size,
background color,text alignment and much more.
To include a style.xml file inside Android project, let us create a new XML file under res/values folder and name it as styles.xml.
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="android:Theme.Light" />
<color name="blue">#0000FF</color>
<color name="white">#FFFFFF</color>
<color name="red">#FF0000</color>
<color name="yellow">#FFF200</color>
<color name="green">#00FF00</color>
<color name="black">#000000</color>
<style name="labelStyleRight">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">0.5</item>
<item name="android:textSize">15dip</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_margin">10dip</item>
<item name="android:gravity">center_vertical|right</item>
</style>
<style name="labelStyleLeft">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">0.5</item>
<item name="android:textSize">15dip</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_margin">10dip</item>
<item name="android:gravity">center_vertical|left</item>
</style>
<style name="textStyle">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">0.5</item>
<item name="android:textSize">15dip</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_margin">10dip</item>
<item name="android:gravity">center_vertical|left</item>
</style>
<style name="textStyleCenter">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">0.5</item>
<item name="android:textSize">15dip</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_margin">10dip</item>
<item name="android:gravity">center</item>
</style>
<style name="textSmallStyle">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_weight">0.5</item>
<item name="android:textSize">10dip</item>
<item name="android:layout_margin">10dip</item>
<item name="android:gravity">center_vertical|left</item>
</style>
<style name="progressStyle">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_margin">10dip</item>
<item name="android:layout_weight">0.5</item>
<item name="android:indeterminateOnly">false</item>
<item name="android:minHeight">20dip</item>
<item name="android:maxHeight">20dip</item>
<item name="android:progress">15</item>
<item name="android:max">100</item>
<item name="android:gravity">center_vertical|left</item>
<item name="android:progressDrawable">@android:drawable/progress_horizontal</item>
<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>
</style>
<style name="imageStyle">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">0.5</item>
<item name="android:src">@drawable/nodata</item>
<item name="android:scaleType">fitStart</item>
<item name="android:layout_margin">10dip</item>
<item name="android:gravity">center_vertical|left</item>
</style>
</resources>
Using the code
1. Permissions in the AndroidManifest.xml file
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_UPDATES"/>
2. The android.telephony.TelephonyManager
Any information related to the telephony services on the device has to be accessed via TelephonyManager class. This class cannot be instantiated directly instead we retrieve a reference to an instance through
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
2.1 The PhoneStateListener object
The PhoneStateListener class is responsible for monitoring changes in specific telephony states
on the smartphone device. We shall override the methods for the state that we wish to receive updates for in the PhoneStateListener object and pass the PhoneStateListener instance, along with bitwise-or of the LISTEN_ flags to TelephonyManager.listen(). The application is now ready for updating any view based on the Telephony events
int events = PhoneStateListener.LISTEN_SIGNAL_STRENGTH |
PhoneStateListener.LISTEN_DATA_ACTIVITY |
PhoneStateListener.LISTEN_CELL_LOCATION |
PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
PhoneStateListener.LISTEN_SERVICE_STATE;
tm.listen(phoneListener, events);
2.1.1 Listening to Phone States
Upon specifying the updates we wish to receive from TelephonyManager. The PhoneStateListener shall handle the callback methods for each change in the phone state. We shall record all such state changes in the corresponding handler methods provided by the PhoneStateListener class and update the status on the view.
NOTE: For demonstration purpose I've discussed only a handful of PhoneStateListener callback methods here in this article. Also the callback implementation methods are oversimplified for the sake of understanding. The methods do no more that updating a TextView or change of thumbnail image in some cases.
2.1.1.1. onCallStateChanged
Callback invoked when device call state changes. In this method we shall record whether the phone is OFFHOOK, RINGING or in the IDLE State based on the State.
TelephonyManager.CALL_STATE_IDLE | Device call state : No activity |
TelephonyManager.CALL_STATE_RINGING | Device call state : A new call arrived and is ringing or waiting |
TelephonyManager.CALL_STATE_OFFHOOK | At least one call exists that is dialing, active, or on hold, and no calls are ringing or waiting |
/*
* Call State Changed
* */
public void onCallStateChanged(int state, String incomingNumber) {
String phoneState = "UNKNOWN";
switch(state){
case TelephonyManager.CALL_STATE_IDLE :
phoneState = "IDLE";
break;
case TelephonyManager.CALL_STATE_RINGING :
phoneState = "Ringing (" + incomingNumber + ") ";
break;
case TelephonyManager.CALL_STATE_OFFHOOK :
phoneState = "Offhook";
break;
}
//Sets the CallState on a textview
setTextViewText(info_ids[INFO_CALL_STATE_INDEX], phoneState);
super.onCallStateChanged(state, incomingNumber);
}
2.1.1.2. onDataConnectionStateChanged
This callback method is invoked whenever there is a change in the data connection state. It can return any of the following 4 possibilities
TelephonyManager.DATA_CONNECTED | Indicates IP traffic should be available |
TelephonyManager.DATA_CONNECTING | Currently setting up a data connection |
TelephonyManager.DATA_DISCONNECTED | Indicates IP Traffic is not available |
TelephonyManager.DATA_SUSPENDED | The connection is up, but IP traffic is temporarily unavailable. For example, in a 2G network, data activity may be suspended when a voice call arrives |
/*
* Cellphone data connection status
* */
public void onDataConnectionStateChanged(int state) {
String phoneState = "UNKNOWN";
switch(state){
case TelephonyManager.DATA_CONNECTED :
phoneState = "Connected";
break;
case TelephonyManager.DATA_CONNECTING :
phoneState = "Connecting..";
break;
case TelephonyManager.DATA_DISCONNECTED :
phoneState = "Disconnected";
break;
case TelephonyManager.DATA_SUSPENDED :
phoneState = "Suspended";
break;
}
//Sets the data connection status on a textview
setTextViewText(info_ids[INFO_CONNECTION_STATE_INDEX], phoneState);
super.onDataConnectionStateChanged(state);
}
2.1.1.3. onDataActivity
This Callback is invoked when data activity state changes. The possible data activity states are as listed below
- TelephonyManager.DATA_ACTIVITY_NONE - No IP Traffic.
- TelephonyManager.DATA_ACTIVITY_IN - Receiving IP Traffic
- TelephonyManager.DATA_ACTIVITY_OUT - Currently sending IP Traffic
- TelephonyManager.DATA_ACTIVITY_INOUT - Currently sending and receiving IP Traffic
- TelephonyManager.DATA_ACTIVITY_DORMANT - Data connection is active, but physical link is down
/*
* Data activity handler
* */
public void onDataActivity(int direction) {
String strDirection = "NONE";
switch(direction){
case TelephonyManager.DATA_ACTIVITY_IN :
strDirection = "IN";
break;
case TelephonyManager.DATA_ACTIVITY_INOUT:
strDirection = "IN-OUT";
break;
case TelephonyManager.DATA_ACTIVITY_DORMANT:
strDirection = "Dormant";
break;
case TelephonyManager.DATA_ACTIVITY_NONE:
strDirection="NONE";
break;
case TelephonyManager.DATA_ACTIVITY_OUT:
strDirection="OUT";
break;
}
//Updates the status Data Activity on a ImageView
setDataDirection(info_ids[INFO_DATA_DIRECTION_INDEX],direction);
super.onDataActivity(direction);
}
The setDataDirection is a user defined method updates a corresponding thumbnail image on a ImageView based on the status of DataActivity .
private void setDataDirection(int id, int direction){
int resid = getDataDirectionRes(direction);
((ImageView)findViewById(id)).setImageResource(resid);
}
2.1.2 End Listening to Phone States
For the application to stop listening to the updates from the TelephonyManager class. We now shall pass the PhoneStateListener instance along with LISTEN_NONE flag to TelephonyManager.listen() method
tm.listen(phoneListener, PhoneStateListener.LISTEN_NONE);
2.2 Querying the Basic Phone Information
The TelephonyManager readily exposes methods to access basic information related to phone such as subscriber information, IMEI Code, Phone no,Network type etc. The code related to this Phone status information is included in the PhoneStatusActivity.java
//Get the IMEI code
String deviceid = tm.getDeviceId();
//Get the phone number string for line 1,For ex: the MSISDN for a GSM phone
String phonenumber = tm.getLine1Number();
//Get the software version number for the device, For ex: the IMEI/SV for GSM phones
String softwareversion = tm.getDeviceSoftwareVersion();
//Get the alphabetic name of current registered operator.
String operatorname = tm.getNetworkOperatorName();
//Get the ISO country code equivalent for the SIM provider's country code.
String simcountrycode = tm.getSimCountryIso();
//Get the Service Provider Name (SPN).
String simoperator = tm.getSimOperatorName();
//Get the serial number of the SIM, if applicable. Return null if it is unavailable.
String simserialno = tm.getSimSerialNumber();
//Get the unique subscriber ID, for example, the IMSI for a GSM phone
String subscriberid = tm.getSubscriberId();
//Get the type indicating the radio technology (network type)
//currently in use on the device for data transmission.EDGE,GPRS,UMTS etc
String networktype = getNetworkTypeString(tm.getNetworkType());
//This indicates the type of radio used to transmit voice calls
//GSM,CDMA etc
String phonetype = getPhoneTypeString(tm.getPhoneType());
The user defined utility methods returns the equivalent string
private String getNetworkTypeString(int type){
String typeString = "Unknown";
switch(type)
{
case TelephonyManager.NETWORK_TYPE_EDGE:
typeString = "EDGE"; break;
case TelephonyManager.NETWORK_TYPE_GPRS:
typeString = "GPRS"; break;
case TelephonyManager.NETWORK_TYPE_UMTS:
typeString = "UMTS"; break;
default:
typeString = "UNKNOWN"; break;
}
return typeString;
}
private String getPhoneTypeString(int type){
String typeString = "Unknown";
switch(type)
{
case TelephonyManager.PHONE_TYPE_GSM: typeString = "GSM"; break;
case TelephonyManager.PHONE_TYPE_NONE: typeString = "UNKNOWN"; break;
default:
typeString = "UNKNOWN"; break;
}
return typeString;
}
In this sample, Once we collect all the required information we shall display the same on a deviceInfo TextView
deviceinfo += ("Device ID: " + deviceid + "\n");
deviceinfo += ("Phone Number: " + phonenumber + "\n");
deviceinfo += ("Software Version: " + softwareversion + "\n");
deviceinfo += ("Operator Name: " + operatorname + "\n");
deviceinfo += ("SIM Country Code: " + simcountrycode + "\n");
deviceinfo += ("SIM Operator: " + simoperator + "\n");
deviceinfo += ("SIM Serial No.: " + simserialno + "\n");
deviceinfo += ("Subscriber ID: " + subscriberid + "\n");
deviceinfo += ("Network Type: " + networktype + "\n");
deviceinfo += ("Phone Type: " + phonetype + "\n");
2.3 Phone Battery
The android.os.BatteryManager class provides information related to
the status of the phone battery in the form of strings and constants.
Ex:
Also we can extract both the current charging status and, if the device is being charged, whether
it's charging via USB or AC charger using
- BatteryManager.BATTERY_PLUGGED_AC - Battery is plugged to an AC source
- BatteryManager.BATTERY_PLUGGED_USB - Battery is plugged to a USB source
- BatteryManager.BATTERY_STATUS_CHARGING - Battery is connected to a power supply and is charging
- BatteryManager.BATTERY_STATUS_DISCHARGING - Battery is discharging
- BatteryManager.BATTERY_STATUS_FULL - Battery charge is complete
3. Activity class for Smartphone Status App
3.1 The StatusActivity class
This is the main activity that is called on the start of the application. This activity is responsible for creating a tab host for hosting PhoneStatusActivity and BatteryStatusActivity. By default PhoneStatusActivity shall be activated.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TabHost host = getTabHost();
//Phone Status Activity
TabSpec statusspec = host.newTabSpec("Phone");
statusspec.setIndicator("Phone",getResources().getDrawable(R.drawable.nphone));
Intent phoneStatusIntent = new Intent(this, PhoneStatusActivity.class);
statusspec.setContent(phoneStatusIntent);
//Battery Status Activity
TabSpec batteryspec = host.newTabSpec("Battery");
batteryspec.setIndicator("Battery", getResources().getDrawable(R.drawable.nbattery));
Intent batteryIntent = new Intent(this, BatteryStatusActivity.class);
batteryspec.setContent(batteryIntent);
// Adding all TabSpec to TabHost
host.addTab(statusspec); //Default tab
host.addTab(batteryspec);
}
3.2 The PhoneStatusActivity class
The PhoneStatusActivity class is responsible for displaying the information received from TelephonyManager as described in the Section 2.1 and Section 2.2.
3.3 The BatteryStatusActivity class
The BatteryStatusActivity class is responsible for displaying the status of battery. The BatteryManager
broadcasts all battery and charging details in a sticky Intent
that includes
the charging status. By hooking in to these intents we can continuosly
monitor the status of the phone battery. To achieve this, we register a
BroadcastReceiver to be run in the main activity thread
(BatteryStatusActivity).The
receiver will be called with any broadcast Intent that matches
filter (Intent.ACTION_BATTERY_CHANGED), in the main application thread.
/*
* Battery Related Broadcast event registration
* */
private void registerBatteryLevelReceiver() {
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(battery_receiver, filter);
}
Once registered, whenever the BroadcastReceiver is receiving an Intent
broadcast (i.e. from BatteryManager), we shall update the status as below
@Override
public void onReceive(Context context, Intent intent) {
boolean isPresent = intent.getBooleanExtra("present", false);
//Battery Technology
String technology = intent.getStringExtra("technology");
//Battery Plugged Information
int plugged = intent.getIntExtra("plugged", -1);
//Battery Scale
int scale = intent.getIntExtra("scale", -1);
//Battery Health
int health = intent.getIntExtra("health", 0);
//Battery Charging Status
int status = intent.getIntExtra("status", 0);
//Battery charging level
int rawlevel = intent.getIntExtra("level", -1);
int level = 0;
Bundle bundle = intent.getExtras();
Log.i("BatteryLevel", bundle.toString());
if (isPresent) {
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
String info = "Battery Level: " + level + "%\n";
info += ("Technology: " + technology + "\n");
info += ("Plugged: " + getPlugTypeString(plugged) + "\n");
info += ("Health: " + getHealthString(health) + "\n");
info += ("Status: " + getStatusString(status) + "\n");
setBatteryLevelText(info);
} else {
setBatteryLevelText("Battery not present!!!");
}
}
More information on best practices for Monitoring the state of battery can be found here
We are done.!! Well almost. Run the application on your Android emulator or best deploy it on your smartphone to see the status of your phone. You can play around by querying different parameters and also by customizing the way the UI is updated as i did in this case for monitoring the Data activity and signal strength.
Happy Coding !!
History
Initial version - 22.03.2012
Download SmartPhoneStatus.zip