/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.telephony; import com.android.internal.telephony.*; import java.util.ArrayList; import java.util.List; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; /** * Provides access to information about the telephony services on * the device. Applications can use the methods in this class to * determine telephony services and states, as well as to access some * types of subscriber information. Applications can also register * a listener to receive notification of telephony state changes. * <p> * You do not instantiate this class directly; instead, you retrieve * a reference to an instance through * {@link android.content.Context#getSystemService * Context.getSystemService(Context.TELEPHONY_SERVICE)}. * <p> * Note that acess to some telephony information is * permission-protected. Your application cannot access the protected * information unless it has the appropriate permissions declared in * its manifest file. Where permissions apply, they are noted in the * the methods through which you access the protected information. */ public class TelephonyManager { private static final String TAG = "TelephonyManager"; private Context mContext; private ITelephonyRegistry mRegistry; /** @hide */ public TelephonyManager(Context context) { mContext = context; mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry")); } /** @hide */ private TelephonyManager() { } private static TelephonyManager sInstance = new TelephonyManager(); /** @hide */ public static TelephonyManager getDefault() { return sInstance; } // // Broadcast Intent actions // /** * Broadcast intent action indicating that the call state (cellular) * on the device has changed. * * <p> * The {@link #EXTRA_STATE} extra indicates the new call state. * If the new state is RINGING, a second extra * {@link #EXTRA_INCOMING_NUMBER} provides the incoming phone number as * a String. * * <p class="note"> * Requires the READ_PHONE_STATE permission. * * <p class="note"> * This was a {@link android.content.Context#sendStickyBroadcast sticky} * broadcast in version 1.0, but it is no longer sticky. * Instead, use {@link #getCallState} to synchronously query the current call state. * * @see #EXTRA_STATE * @see #EXTRA_INCOMING_NUMBER * @see #getCallState */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; /** * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast * for a String containing the new call state. * * @see #EXTRA_STATE_IDLE * @see #EXTRA_STATE_RINGING * @see #EXTRA_STATE_OFFHOOK * * <p class="note"> * Retrieve with * {@link android.content.Intent#getStringExtra(String)}. */ public static final String EXTRA_STATE = Phone.STATE_KEY; /** * Value used with {@link #EXTRA_STATE} corresponding to * {@link #CALL_STATE_IDLE}. */ public static final String EXTRA_STATE_IDLE = Phone.State.IDLE.toString(); /** * Value used with {@link #EXTRA_STATE} corresponding to * {@link #CALL_STATE_RINGING}. */ public static final String EXTRA_STATE_RINGING = Phone.State.RINGING.toString(); /** * Value used with {@link #EXTRA_STATE} corresponding to * {@link #CALL_STATE_OFFHOOK}. */ public static final String EXTRA_STATE_OFFHOOK = Phone.State.OFFHOOK.toString(); /** * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast * for a String containing the incoming phone number. * Only valid when the new call state is RINGING. * * <p class="note"> * Retrieve with * {@link android.content.Intent#getStringExtra(String)}. */ public static final String EXTRA_INCOMING_NUMBER = "incoming_number"; // // // Device Info // // /** * Returns the software version number for the device, for example, * the IMEI/SV for GSM phones. * * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceSoftwareVersion() { try { return getSubscriberInfo().getDeviceSvn(); } catch (RemoteException ex) { } return null; } /** * Returns the unique device ID, for example,the IMEI for GSM * phones. * * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceId() { try { return getSubscriberInfo().getDeviceId(); } catch (RemoteException ex) { } return null; } /** * Returns the current location of the device. * * <p>Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION * ACCESS_COARSE_LOCATION}. */ public CellLocation getCellLocation() { try { Bundle bundle = getITelephony().getCellLocation(); return CellLocation.newFromBundle(bundle); } catch (RemoteException ex) { } return null; } /** * Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged * PhoneStateListener.onCellLocationChanged} will be called on location updates. * * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES * CONTROL_LOCATION_UPDATES} * * @hide */ public void enableLocationUpdates() { try { getITelephony().enableLocationUpdates(); } catch (RemoteException ex) { } } /** * Disables location update notifications. {@link PhoneStateListener#onCellLocationChanged * PhoneStateListener.onCellLocationChanged} will be called on location updates. * * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES * CONTROL_LOCATION_UPDATES} * * @hide */ public void disableLocationUpdates() { try { getITelephony().disableLocationUpdates(); } catch (RemoteException ex) { } } /** * Returns the neighboring cell information of the device. * * @return List of NeighboringCellInfo or null if info unavailable. * * <p>Requires Permission: * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES} */ public List<NeighboringCellInfo> getNeighboringCellInfo() { try { return getITelephony().getNeighboringCellInfo(); } catch (RemoteException ex) { } return null; } /** * No phone module */ public static final int PHONE_TYPE_NONE = 0; /** * GSM phone */ public static final int PHONE_TYPE_GSM = 1; /** * Returns a constant indicating the device phone type. * * @see #PHONE_TYPE_NONE * @see #PHONE_TYPE_GSM */ public int getPhoneType() { // in the future, we should really check this return PHONE_TYPE_GSM; } // // // Current Network // // /** * Returns the alphabetic name of current registered operator. * <p> * Availability: Only when user is registered to a network */ public String getNetworkOperatorName() { return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA); } /** * Returns the numeric name (MCC+MNC) of current registered operator. * <p> * Availability: Only when user is registered to a network */ public String getNetworkOperator() { return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC); } /** * Returns true if the device is considered roaming on the current * network, for GSM purposes. * <p> * Availability: Only when user registered to a network */ public boolean isNetworkRoaming() { return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING)); } /** * Returns the ISO country code equivilent of the current registered * operator's MCC (Mobile Country Code). * <p> * Availability: Only when user is registered to a network */ public String getNetworkCountryIso() { return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY); } /** Network type is unknown */ public static final int NETWORK_TYPE_UNKNOWN = 0; /** Current network is GPRS */ public static final int NETWORK_TYPE_GPRS = 1; /** Current network is EDGE */ public static final int NETWORK_TYPE_EDGE = 2; /** Current network is UMTS */ public static final int NETWORK_TYPE_UMTS = 3; /** * Returns a constant indicating the radio technology (network type) * currently in use on the device. * @return the network type * * @see #NETWORK_TYPE_UNKNOWN * @see #NETWORK_TYPE_GPRS * @see #NETWORK_TYPE_EDGE * @see #NETWORK_TYPE_UMTS */ public int getNetworkType() { String prop = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE); if ("GPRS".equals(prop)) { return NETWORK_TYPE_GPRS; } else if ("EDGE".equals(prop)) { return NETWORK_TYPE_EDGE; } else if ("UMTS".equals(prop)) { return NETWORK_TYPE_UMTS; } else { return NETWORK_TYPE_UNKNOWN; } } /** * Returns a string representation of the radio technology (network type) * currently in use on the device. * @return the name of the radio technology * * @hide pending API council review */ public String getNetworkTypeName() { switch (getNetworkType()) { case NETWORK_TYPE_GPRS: return "GPRS"; case NETWORK_TYPE_EDGE: return "EDGE"; case NETWORK_TYPE_UMTS: return "UMTS"; default: return "UNKNOWN"; } } // // // SIM Card // // /** SIM card state: Unknown. Signifies that the SIM is in transition * between states. For example, when the user inputs the SIM pin * under PIN_REQUIRED state, a query for sim status returns * this state before turning to SIM_STATE_READY. */ public static final int SIM_STATE_UNKNOWN = 0; /** SIM card state: no SIM card is available in the device */ public static final int SIM_STATE_ABSENT = 1; /** SIM card state: Locked: requires the user's SIM PIN to unlock */ public static final int SIM_STATE_PIN_REQUIRED = 2; /** SIM card state: Locked: requires the user's SIM PUK to unlock */ public static final int SIM_STATE_PUK_REQUIRED = 3; /** SIM card state: Locked: requries a network PIN to unlock */ public static final int SIM_STATE_NETWORK_LOCKED = 4; /** SIM card state: Ready */ public static final int SIM_STATE_READY = 5; /** * Returns a constant indicating the state of the * device SIM card. * * @see #SIM_STATE_UNKNOWN * @see #SIM_STATE_ABSENT * @see #SIM_STATE_PIN_REQUIRED * @see #SIM_STATE_PUK_REQUIRED * @see #SIM_STATE_NETWORK_LOCKED * @see #SIM_STATE_READY */ public int getSimState() { String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE); if ("ABSENT".equals(prop)) { return SIM_STATE_ABSENT; } else if ("PIN_REQUIRED".equals(prop)) { return SIM_STATE_PIN_REQUIRED; } else if ("PUK_REQUIRED".equals(prop)) { return SIM_STATE_PUK_REQUIRED; } else if ("NETWORK_LOCKED".equals(prop)) { return SIM_STATE_NETWORK_LOCKED; } else if ("READY".equals(prop)) { return SIM_STATE_READY; } else { return SIM_STATE_UNKNOWN; } } /** * Returns the MCC+MNC (mobile country code + mobile network code) of the * provider of the SIM. 5 or 6 decimal digits. * <p> * Availability: SIM state must be {@link #SIM_STATE_READY} * * @see #getSimState */ public String getSimOperator() { return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC); } /** * Returns the Service Provider Name (SPN). * <p> * Availability: SIM state must be {@link #SIM_STATE_READY} * * @see #getSimState */ public String getSimOperatorName() { return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA); } /** * Returns the ISO country code equivalent for the SIM provider's country code. */ public String getSimCountryIso() { return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ISO_COUNTRY); } /** * Returns the serial number of the SIM, if applicable. * <p> * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSimSerialNumber() { try { return getSubscriberInfo().getSimSerialNumber(); } catch (RemoteException ex) { } return null; } // // // Subscriber Info // // /** * Returns the unique subscriber ID, for example, the IMSI for a GSM phone. * <p> * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSubscriberId() { try { return getSubscriberInfo().getSubscriberId(); } catch (RemoteException ex) { } return null; } /** * Returns the phone number string for line 1, for example, the MSISDN * for a GSM phone. * <p> * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getLine1Number() { try { return getSubscriberInfo().getLine1Number(); } catch (RemoteException ex) { } return null; } /** * Returns the alphabetic identifier associated with the line 1 number. * <p> * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * @hide * nobody seems to call this. */ public String getLine1AlphaTag() { try { return getSubscriberInfo().getLine1AlphaTag(); } catch (RemoteException ex) { } return null; } /** * Returns the voice mail number. * <p> * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailNumber() { try { return getSubscriberInfo().getVoiceMailNumber(); } catch (RemoteException ex) { } return null; } /** * Retrieves the alphabetic identifier associated with the voice * mail number. * <p> * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailAlphaTag() { try { return getSubscriberInfo().getVoiceMailAlphaTag(); } catch (RemoteException ex) { } return null; } private IPhoneSubInfo getSubscriberInfo() { // get it each time because that process crashes a lot return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo")); } /** Device call state: No activity. */ public static final int CALL_STATE_IDLE = 0; /** Device call state: Ringing. A new call arrived and is * ringing or waiting. In the latter case, another call is * already active. */ public static final int CALL_STATE_RINGING = 1; /** Device call state: Off-hook. At least one call exists * that is dialing, active, or on hold, and no calls are ringing * or waiting. */ public static final int CALL_STATE_OFFHOOK = 2; /** * Returns a constant indicating the call state (cellular) on the device. */ public int getCallState() { try { return getITelephony().getCallState(); } catch (RemoteException ex) { // the phone process is restarting. return CALL_STATE_IDLE; } } /** Data connection activity: No traffic. */ public static final int DATA_ACTIVITY_NONE = 0x00000000; /** Data connection activity: Currently receiving IP PPP traffic. */ public static final int DATA_ACTIVITY_IN = 0x00000001; /** Data connection activity: Currently sending IP PPP traffic. */ public static final int DATA_ACTIVITY_OUT = 0x00000002; /** Data connection activity: Currently both sending and receiving * IP PPP traffic. */ public static final int DATA_ACTIVITY_INOUT = DATA_ACTIVITY_IN | DATA_ACTIVITY_OUT; /** * Returns a constant indicating the type of activity on a data connection * (cellular). * * @see #DATA_ACTIVITY_NONE * @see #DATA_ACTIVITY_IN * @see #DATA_ACTIVITY_OUT * @see #DATA_ACTIVITY_INOUT */ public int getDataActivity() { try { return getITelephony().getDataActivity(); } catch (RemoteException ex) { // the phone process is restarting. return DATA_ACTIVITY_NONE; } } /** Data connection state: Disconnected. IP traffic not available. */ public static final int DATA_DISCONNECTED = 0; /** Data connection state: Currently setting up a data connection. */ public static final int DATA_CONNECTING = 1; /** Data connection state: Connected. IP traffic should be available. */ public static final int DATA_CONNECTED = 2; /** Data connection state: 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. */ public static final int DATA_SUSPENDED = 3; /** * Returns a constant indicating the current data connection state * (cellular). * * @see #DATA_DISCONNECTED * @see #DATA_CONNECTING * @see #DATA_CONNECTED * @see #DATA_SUSPENDED */ public int getDataState() { try { return getITelephony().getDataState(); } catch (RemoteException ex) { // the phone process is restarting. return DATA_DISCONNECTED; } } private ITelephony getITelephony() { return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); } // // // PhoneStateListener // // /** * Registers a listener object to receive notification of changes * in specified telephony states. * <p> * To register a listener, pass a {@link PhoneStateListener} * and specify at least one telephony state of interest in * the events argument. * * At registration, and when a specified telephony state * changes, the telephony manager invokes the appropriate * callback method on the listener object and passes the * current (udpated) values. * <p> * To unregister a listener, pass the listener object and set the * events argument to * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0). * * @param listener The {@link PhoneStateListener} object to register * (or unregister) * @param events The telephony state(s) of interest to the listener, * as a bitwise-OR combination of {@link PhoneStateListener} * LISTEN_ flags. */ public void listen(PhoneStateListener listener, int events) { String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>"; try { Boolean notifyNow = (getITelephony() != null); mRegistry.listen(pkgForDebug, listener.callback, events, notifyNow); } catch (RemoteException ex) { // system process dead } } }