OSDN Git Service

Added a private apis jar that includes explicitly supported APIs that are not useful...
[android-x86/frameworks-base.git] / telephony / java / android / telephony / TelephonyManager.java
old mode 100755 (executable)
new mode 100644 (file)
index fa4b7cd..3ab7000
 
 package android.telephony;
 
+import android.annotation.PrivateApi;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.telephony.Rlog;
 import android.util.Log;
 
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.ITelephonyListener;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
@@ -34,6 +39,7 @@ import com.android.internal.telephony.TelephonyProperties;
 
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -59,19 +65,52 @@ import java.util.regex.Pattern;
 public class TelephonyManager {
     private static final String TAG = "TelephonyManager";
 
-    private static Context sContext;
     private static ITelephonyRegistry sRegistry;
 
+    private final HashMap<CallStateListener,Listener> mListeners
+            = new HashMap<CallStateListener,Listener>();
+    private final Context mContext;
+
+    private static class Listener extends ITelephonyListener.Stub {
+        final CallStateListener mListener;
+        private static final int WHAT = 1;
+
+        private Handler mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                mListener.onCallStateChanged(msg.arg1, msg.arg2, (String)msg.obj);
+            }
+        };
+
+        Listener(CallStateListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onUpdate(final int callId, final int state, final String number) {
+            if (mHandler != null) {
+                mHandler.sendMessage(mHandler.obtainMessage(WHAT, callId, state, number));
+            }
+        }
+
+        void clearQueue() {
+            mHandler.removeMessages(WHAT);
+
+            // Don't accept more incoming binder calls either.
+            mHandler = null;
+        }
+    }
+
     /** @hide */
     public TelephonyManager(Context context) {
-        if (sContext == null) {
-            Context appContext = context.getApplicationContext();
-            if (appContext != null) {
-                sContext = appContext;
-            } else {
-                sContext = context;
-            }
+        Context appContext = context.getApplicationContext();
+        if (appContext != null) {
+            mContext = appContext;
+        } else {
+            mContext = context;
+        }
 
+        if (sRegistry == null) {
             sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                     "telephony.registry"));
         }
@@ -79,6 +118,7 @@ public class TelephonyManager {
 
     /** @hide */
     private TelephonyManager() {
+        mContext = null;
     }
 
     private static TelephonyManager sInstance = new TelephonyManager();
@@ -125,6 +165,49 @@ public class TelephonyManager {
             "android.intent.action.PHONE_STATE";
 
     /**
+     * The Phone app sends this intent when a user opts to respond-via-message during an incoming
+     * call. By default, the device's default SMS app consumes this message and sends a text message
+     * to the caller. A third party app can also provide this functionality by consuming this Intent
+     * with a {@link android.app.Service} and sending the message using its own messaging system.
+     * <p>The intent contains a URI (available from {@link android.content.Intent#getData})
+     * describing the recipient, using either the {@code sms:}, {@code smsto:}, {@code mms:},
+     * or {@code mmsto:} URI schema. Each of these URI schema carry the recipient information the
+     * same way: the path part of the URI contains the recipient's phone number or a comma-separated
+     * set of phone numbers if there are multiple recipients. For example, {@code
+     * smsto:2065551234}.</p>
+     *
+     * <p>The intent may also contain extras for the message text (in {@link
+     * android.content.Intent#EXTRA_TEXT}) and a message subject
+     * (in {@link android.content.Intent#EXTRA_SUBJECT}).</p>
+     *
+     * <p class="note"><strong>Note:</strong>
+     * The intent-filter that consumes this Intent needs to be in a {@link android.app.Service}
+     * that requires the
+     * permission {@link android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE}.</p>
+     * <p>For example, the service that receives this intent can be declared in the manifest file
+     * with an intent filter like this:</p>
+     * <pre>
+     * &lt;!-- Service that delivers SMS messages received from the phone "quick response" -->
+     * &lt;service android:name=".HeadlessSmsSendService"
+     *          android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+     *          android:exported="true" >
+     *   &lt;intent-filter>
+     *     &lt;action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+     *     &lt;category android:name="android.intent.category.DEFAULT" />
+     *     &lt;data android:scheme="sms" />
+     *     &lt;data android:scheme="smsto" />
+     *     &lt;data android:scheme="mms" />
+     *     &lt;data android:scheme="mmsto" />
+     *   &lt;/intent-filter>
+     * &lt;/service></pre>
+     * <p>
+     * Output: nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_RESPOND_VIA_MESSAGE =
+            "android.intent.action.RESPOND_VIA_MESSAGE";
+
+    /**
      * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
      * for a String containing the new call state.
      *
@@ -211,7 +294,14 @@ public class TelephonyManager {
 
     /**
      * Returns the current location of the device.
-     * Return null if current location is not available.
+     *<p>
+     * If there is only one radio in the device and that radio has an LTE connection,
+     * this method will return null. The implementation must not to try add LTE
+     * identifiers into the existing cdma/gsm classes.
+     *<p>
+     * In the future this call will be deprecated.
+     *<p>
+     * @return Current location of the device or null if not available.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
@@ -220,6 +310,7 @@ public class TelephonyManager {
     public CellLocation getCellLocation() {
         try {
             Bundle bundle = getITelephony().getCellLocation();
+            if (bundle.isEmpty()) return null;
             CellLocation cl = CellLocation.newFromBundle(bundle);
             if (cl.isEmpty())
                 return null;
@@ -266,8 +357,11 @@ public class TelephonyManager {
     }
 
     /**
-     * Returns the neighboring cell information of the device.
-     *
+     * Returns the neighboring cell information of the device. The getAllCellInfo is preferred
+     * and use this only if getAllCellInfo return nulls or an empty list.
+     *<p>
+     * In the future this call will be deprecated.
+     *<p>
      * @return List of NeighboringCellInfo or null if info unavailable.
      *
      * <p>Requires Permission:
@@ -275,7 +369,7 @@ public class TelephonyManager {
      */
     public List<NeighboringCellInfo> getNeighboringCellInfo() {
         try {
-            return getITelephony().getNeighboringCellInfo();
+            return getITelephony().getNeighboringCellInfo(mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -360,7 +454,7 @@ public class TelephonyManager {
      * This function returns the type of the phone, depending
      * on the network mode.
      *
-     * @param network mode
+     * @param networkMode
      * @return Phone Type
      *
      * @hide
@@ -376,12 +470,14 @@ public class TelephonyManager {
         case RILConstants.NETWORK_MODE_GSM_ONLY:
         case RILConstants.NETWORK_MODE_WCDMA_ONLY:
         case RILConstants.NETWORK_MODE_GSM_UMTS:
+        case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_GSM;
 
         // Use CDMA Phone for the global mode including CDMA
         case RILConstants.NETWORK_MODE_GLOBAL:
         case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
-        case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_CDMA;
 
         case RILConstants.NETWORK_MODE_LTE_ONLY:
@@ -410,7 +506,7 @@ public class TelephonyManager {
                 cmdline = new String(buffer, 0, count);
             }
         } catch (IOException e) {
-            Log.d(TAG, "No /proc/cmdline exception=" + e);
+            Rlog.d(TAG, "No /proc/cmdline exception=" + e);
         } finally {
             if (is != null) {
                 try {
@@ -419,7 +515,7 @@ public class TelephonyManager {
                 }
             }
         }
-        Log.d(TAG, "/proc/cmdline=" + cmdline);
+        Rlog.d(TAG, "/proc/cmdline=" + cmdline);
         return cmdline;
     }
 
@@ -466,7 +562,7 @@ public class TelephonyManager {
             }
         }
 
-        Log.d(TAG, "getLteOnCdmaMode=" + retVal + " curVal=" + curVal +
+        Rlog.d(TAG, "getLteOnCdmaMode=" + retVal + " curVal=" + curVal +
                 " product_type='" + productType +
                 "' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'");
         return retVal;
@@ -556,6 +652,13 @@ public class TelephonyManager {
     public static final int NETWORK_TYPE_HSPAP = 15;
 
     /**
+     * @return the NETWORK_TYPE_xxxx for current data connection.
+     */
+    public int getNetworkType() {
+        return getDataNetworkType();
+    }
+
+    /**
      * Returns a constant indicating the radio technology (network type)
      * currently in use on the device for data transmission.
      * @return the network type
@@ -576,12 +679,37 @@ public class TelephonyManager {
      * @see #NETWORK_TYPE_LTE
      * @see #NETWORK_TYPE_EHRPD
      * @see #NETWORK_TYPE_HSPAP
+     *
+     * @hide
      */
-    public int getNetworkType() {
+    public int getDataNetworkType() {
         try{
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getNetworkType();
+                return telephony.getDataNetworkType();
+            } else {
+                // This can happen when the ITelephony interface is not up yet.
+                return NETWORK_TYPE_UNKNOWN;
+            }
+        } catch(RemoteException ex) {
+            // This shouldn't happen in the normal case
+            return NETWORK_TYPE_UNKNOWN;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return NETWORK_TYPE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Returns the NETWORK_TYPE_xxxx for voice
+     *
+     * @hide
+     */
+    public int getVoiceNetworkType() {
+        try{
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getVoiceNetworkType();
             } else {
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
@@ -807,8 +935,8 @@ public class TelephonyManager {
      * is a tri-state return value as for a period of time
      * the mode may be unknown.
      *
-     * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
-     * or {@link Phone#LTE_ON_CDMA_TRUE}
+     * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
+     * or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
      *
      * @hide
      */
@@ -849,6 +977,24 @@ public class TelephonyManager {
     }
 
     /**
+     * Returns the Group Identifier Level1 for a GSM phone.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     */
+    public String getGroupIdLevel1() {
+        try {
+            return getSubscriberInfo().getGroupIdLevel1();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
      * Returns the phone number string for line 1, for example, the MSISDN
      * for a GSM phone. Return null if it is unavailable.
      * <p>
@@ -1164,9 +1310,9 @@ public class TelephonyManager {
      *               LISTEN_ flags.
      */
     public void listen(PhoneStateListener listener, int events) {
-        String pkgForDebug = sContext != null ? sContext.getPackageName() : "<unknown>";
+        String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
         try {
-            Boolean notifyNow = (getITelephony() != null);
+            Boolean notifyNow = true;
             sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
         } catch (RemoteException ex) {
             // system process dead
@@ -1242,8 +1388,8 @@ public class TelephonyManager {
      * @hide pending API review
      */
     public boolean isVoiceCapable() {
-        if (sContext == null) return true;
-        return sContext.getResources().getBoolean(
+        if (mContext == null) return true;
+        return mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_voice_capable);
     }
 
@@ -1259,20 +1405,31 @@ public class TelephonyManager {
      * @hide pending API review
      */
     public boolean isSmsCapable() {
-        if (sContext == null) return true;
-        return sContext.getResources().getBoolean(
+        if (mContext == null) return true;
+        return mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_sms_capable);
     }
 
     /**
-     * Returns all observed cell information of the device.
-     *
+     * Returns all observed cell information from all radios on the
+     * device including the primary and neighboring cells. This does
+     * not cause or change the rate of PhoneStateListner#onCellInfoChanged.
+     *<p>
+     * The list can include one or more of {@link android.telephony.CellInfoGsm CellInfoGsm},
+     * {@link android.telephony.CellInfoCdma CellInfoCdma},
+     * {@link android.telephony.CellInfoLte CellInfoLte} and
+     * {@link android.telephony.CellInfoWcdma CellInfoCdma} in any combination.
+     * Specifically on devices with multiple radios it is typical to see instances of
+     * one or more of any these in the list. In addition 0, 1 or more CellInfo
+     * objects may return isRegistered() true.
+     *<p>
+     * This is preferred over using getCellLocation although for older
+     * devices this may return null in which case getCellLocation should
+     * be called.
+     *<p>
      * @return List of CellInfo or null if info unavailable.
      *
-     * <p>Requires Permission:
-     * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES}
-     *
-     * @hide pending API review
+     * <p>Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
      */
     public List<CellInfo> getAllCellInfo() {
         try {
@@ -1283,4 +1440,435 @@ public class TelephonyManager {
             return null;
         }
     }
+
+    /**
+     * Sets the minimum time in milli-seconds between {@link PhoneStateListener#onCellInfoChanged
+     * PhoneStateListener.onCellInfoChanged} will be invoked.
+     *<p>
+     * The default, 0, means invoke onCellInfoChanged when any of the reported
+     * information changes. Setting the value to INT_MAX(0x7fffffff) means never issue
+     * A onCellInfoChanged.
+     *<p>
+     * @param rateInMillis the rate
+     *
+     * @hide
+     */
+    public void setCellInfoListRate(int rateInMillis) {
+        try {
+            getITelephony().setCellInfoListRate(rateInMillis);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+    }
+
+    /**
+     * Returns the MMS user agent.
+     */
+    public String getMmsUserAgent() {
+        if (mContext == null) return null;
+        return mContext.getResources().getString(
+                com.android.internal.R.string.config_mms_user_agent);
+    }
+
+    /**
+     * Returns the MMS user agent profile URL.
+     */
+    public String getMmsUAProfUrl() {
+        if (mContext == null) return null;
+        return mContext.getResources().getString(
+                com.android.internal.R.string.config_mms_user_agent_profile_url);
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void dial(String number) {
+        try {
+            getITelephony().dial(number);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#dial", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void call(String callingPackage, String number) {
+        try {
+            getITelephony().call(callingPackage, number);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#call", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean showCallScreen() {
+        try {
+            return getITelephony().showCallScreen();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#showCallScreen", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean showCallScreenWithDialpad(boolean showDialpad) {
+        try {
+            return getITelephony().showCallScreenWithDialpad(showDialpad);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#showCallScreenWithDialpad", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean endCall() {
+        try {
+            return getITelephony().endCall();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#endCall", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void answerRingingCall() {
+        try {
+            getITelephony().answerRingingCall();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#answerRingingCall", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void toggleHold() {
+        try {
+            getITelephony().toggleHold();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#toggleHold", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void merge() {
+        try {
+            getITelephony().merge();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#merge", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void swap() {
+        try {
+            getITelephony().swap();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#swap", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void mute(boolean mute) {
+        try {
+            getITelephony().mute(mute);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#mute", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void silenceRinger() {
+        try {
+            getITelephony().silenceRinger();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#silenceRinger", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean isOffhook() {
+        try {
+            return getITelephony().isOffhook();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isOffhook", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean isRinging() {
+        try {
+            return getITelephony().isRinging();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isRinging", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean isIdle() {
+        try {
+            return getITelephony().isIdle();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isIdle", e);
+        }
+        return true;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean isRadioOn() {
+        try {
+            return getITelephony().isRadioOn();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isRadioOn", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean isSimPinEnabled() {
+        try {
+            return getITelephony().isSimPinEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isSimPinEnabled", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void cancelMissedCallsNotification() {
+        try {
+            getITelephony().cancelMissedCallsNotification();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#cancelMissedCallsNotification", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean supplyPin(String pin) {
+        try {
+            return getITelephony().supplyPin(pin);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#supplyPin", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean supplyPuk(String puk, String pin) {
+        try {
+            return getITelephony().supplyPuk(puk, pin);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#supplyPuk", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public int[] supplyPinReportResult(String pin) {
+        try {
+            return getITelephony().supplyPinReportResult(pin);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#supplyPinReportResult", e);
+        }
+        return new int[0];
+    }
+
+    /** @hide */
+    @PrivateApi
+    public int[] supplyPukReportResult(String puk, String pin) {
+        try {
+            return getITelephony().supplyPukReportResult(puk, pin);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#]", e);
+        }
+        return new int[0];
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean handlePinMmi(String dialString) {
+        try {
+            return getITelephony().handlePinMmi(dialString);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#handlePinMmi", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void toggleRadioOnOff() {
+        try {
+            getITelephony().toggleRadioOnOff();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#toggleRadioOnOff", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean setRadio(boolean turnOn) {
+        try {
+            return getITelephony().setRadio(turnOn);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#setRadio", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean setRadioPower(boolean turnOn) {
+        try {
+            return getITelephony().setRadioPower(turnOn);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#setRadioPower", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void updateServiceLocation() {
+        try {
+            getITelephony().updateServiceLocation();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#updateServiceLocation", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public int enableApnType(String type) {
+        try {
+            return getITelephony().enableApnType(type);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#enableApnType", e);
+        }
+        return PhoneConstants.APN_REQUEST_FAILED;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public int disableApnType(String type) {
+        try {
+            return getITelephony().disableApnType(type);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#disableApnType", e);
+        }
+        return PhoneConstants.APN_REQUEST_FAILED;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean enableDataConnectivity() {
+        try {
+            return getITelephony().enableDataConnectivity();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#enableDataConnectivity", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean disableDataConnectivity() {
+        try {
+            return getITelephony().disableDataConnectivity();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#disableDataConnectivity", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean isDataConnectivityPossible() {
+        try {
+            return getITelephony().isDataConnectivityPossible();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isDataConnectivityPossible", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public boolean needsOtaServiceProvisioning() {
+        try {
+            return getITelephony().needsOtaServiceProvisioning();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#needsOtaServiceProvisioning", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void playDtmfTone(char digit, boolean timedShortCode) {
+        try {
+            getITelephony().playDtmfTone(digit, timedShortCode);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#playDtmfTone", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void stopDtmfTone() {
+        try {
+            getITelephony().stopDtmfTone();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#stopDtmfTone", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void addCallStateListener(CallStateListener listener) {
+        try {
+            if (listener == null) {
+                throw new RuntimeException("Listener can't be null");
+            }
+            if (!mListeners.containsKey(listener)) {
+                final Listener l = new Listener(listener);
+                mListeners.put(listener, l);
+                getITelephony().addListener(l);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#addListener", e);
+        }
+    }
+
+    /** @hide */
+    @PrivateApi
+    public void removeCallStateListener(CallStateListener listener) {
+        try {
+            final Listener l = mListeners.remove(listener);
+            if (l != null) {
+                // Make sure that no callbacks that are already in flight come.
+                l.clearQueue();
+                getITelephony().removeListener(l);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#removeListener", e);
+        }
+    }
 }