Added event handling for Modem Power Level indication.
Added APIs for data connection Enable/Disable, Set APN, check selected APN.

Merging kwd commit 7c5815e9539184e60885834d5f3608c04f5fa012 with changes.
Update Common's make file.
Update data enable API call.

Change-Id: I26453f4a15b6f78e51fd360b18ca625047a648d6

Conflicts:
	Tools/sl4a/Common/Android.mk
diff --git a/Common/Android.mk b/Common/Android.mk
index bdeaca3..cb2b8a9 100644
--- a/Common/Android.mk
+++ b/Common/Android.mk
@@ -6,8 +6,8 @@
 
 LOCAL_MODULE := sl4a.Common
 
-LOCAL_JAVA_LIBRARIES := libGoogleAnalytics
-LOCAL_STATIC_JAVA_LIBRARIES := guava android-common sl4a.Utils
+LOCAL_STATIC_JAVA_LIBRARIES := guava android-common sl4a.Utils libGoogleAnalytics
+LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src/com/googlecode/android_scripting)
 LOCAL_SRC_FILES += $(call all-java-files-under, src/org/apache/commons/codec)
diff --git a/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java b/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java
index 24495fe..35eb5fb 100644
--- a/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java
@@ -28,13 +28,25 @@
 import android.telephony.NeighboringCellInfo;

 import android.telephony.PhoneStateListener;

 import android.telephony.TelephonyManager;

+import android.telephony.PreciseCallState;

+import android.net.ConnectivityManager;

+import android.provider.Telephony;

+import android.telephony.DataConnectionRealTimeInfo;

+

+import com.android.internal.telephony.TelephonyProperties;

+

+import android.content.ContentValues;

+import android.os.SystemProperties;

 

 import com.googlecode.android_scripting.MainThread;

 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;

 import com.googlecode.android_scripting.rpc.Rpc;

+import com.googlecode.android_scripting.rpc.RpcDefault;

 import com.googlecode.android_scripting.rpc.RpcParameter;

 import com.googlecode.android_scripting.rpc.RpcStartEvent;

 import com.googlecode.android_scripting.rpc.RpcStopEvent;

+import com.googlecode.android_scripting.Log;

+import com.googlecode.android_scripting.rpc.RpcOptional;

 

 import java.io.UnsupportedEncodingException;

 import java.lang.reflect.Field;

@@ -50,237 +62,517 @@
  */

 public class PhoneFacade extends RpcReceiver {

 

-  private final AndroidFacade mAndroidFacade;

-  private final EventFacade mEventFacade;

-  private final TelephonyManager mTelephonyManager;

-  private final Bundle mPhoneState;

-  private final Service mService;

-  private PhoneStateListener mPhoneStateListener;

+    private final AndroidFacade mAndroidFacade;

+    private final EventFacade mEventFacade;

+    private final TelephonyManager mTelephonyManager;

+    private final Bundle mPhoneState;

+    private final Service mService;

+    private PhoneStateListener mPhoneStateListener;

+    private final ConnectivityManager mConnect;

+    private final Bundle mModemPowerLevel;

+    private final Bundle mPreciseCallState;

 

-  public PhoneFacade(FacadeManager manager) {

-    super(manager);

-    mService = manager.getService();

-    mTelephonyManager = (TelephonyManager) mService.getSystemService(Context.TELEPHONY_SERVICE);

-    mAndroidFacade = manager.getReceiver(AndroidFacade.class);

-    mEventFacade = manager.getReceiver(EventFacade.class);

-    mPhoneState = new Bundle();

-    mPhoneStateListener = MainThread.run(mService, new Callable<PhoneStateListener>() {

-      @Override

-      public PhoneStateListener call() throws Exception {

-        return new PhoneStateListener() {

-          @Override

-          public void onCallStateChanged(int state, String incomingNumber) {

-            mPhoneState.putString("incomingNumber", incomingNumber);

-            switch (state) {

-            case TelephonyManager.CALL_STATE_IDLE:

-              mPhoneState.putString("state", "idle");

-              break;

-            case TelephonyManager.CALL_STATE_OFFHOOK:

-              mPhoneState.putString("state", "offhook");

-              break;

-            case TelephonyManager.CALL_STATE_RINGING:

-              mPhoneState.putString("state", "ringing");

-              break;

+    private final int POWER_STATE_LOW = 1;

+    private final int POWER_STATE_MEDIUM = 2;

+    private final int POWER_STATE_HIGH = 3;

+    private final int POWER_STATE_UNKNOWN = Integer.MAX_VALUE;

+

+    private static final String[] sProjection = new String[] {

+            Telephony.Carriers._ID, // 0

+            Telephony.Carriers.NAME, // 1

+            Telephony.Carriers.APN, // 2

+            Telephony.Carriers.PROXY, // 3

+            Telephony.Carriers.PORT, // 4

+            Telephony.Carriers.USER, // 5

+            Telephony.Carriers.SERVER, // 6

+            Telephony.Carriers.PASSWORD, // 7

+            Telephony.Carriers.MMSC, // 8

+            Telephony.Carriers.MCC, // 9

+            Telephony.Carriers.MNC, // 10

+            Telephony.Carriers.NUMERIC, // 11

+            Telephony.Carriers.MMSPROXY,// 12

+            Telephony.Carriers.MMSPORT, // 13

+            Telephony.Carriers.AUTH_TYPE, // 14

+            Telephony.Carriers.TYPE, // 15

+            Telephony.Carriers.PROTOCOL, // 16

+            Telephony.Carriers.CARRIER_ENABLED, // 17

+            Telephony.Carriers.BEARER, // 18

+            Telephony.Carriers.ROAMING_PROTOCOL, // 19

+            Telephony.Carriers.MVNO_TYPE, // 20

+            Telephony.Carriers.MVNO_MATCH_DATA

+            // 21

+    };

+

+    public PhoneFacade(FacadeManager manager) {

+        super(manager);

+        mService = manager.getService();

+        mTelephonyManager = (TelephonyManager) mService

+                .getSystemService(Context.TELEPHONY_SERVICE);

+        mConnect = (ConnectivityManager) mService

+                .getSystemService(Context.CONNECTIVITY_SERVICE);

+        mAndroidFacade = manager.getReceiver(AndroidFacade.class);

+        mEventFacade = manager.getReceiver(EventFacade.class);

+        mPhoneState = new Bundle();

+        mModemPowerLevel = new Bundle();

+        mModemPowerLevel.putLong("time", 0);

+        mModemPowerLevel.putInt("power_level", POWER_STATE_UNKNOWN);

+        mPreciseCallState = new Bundle();

+        mPreciseCallState.putString("CallState", "");

+

+        mPhoneStateListener = MainThread.run(mService,

+                new Callable<PhoneStateListener>() {

+                    @Override

+                    public PhoneStateListener call() throws Exception {

+                        return new PhoneStateListener() {

+                            @Override

+                            public void onCallStateChanged(int state,

+                                    String incomingNumber) {

+                                mPhoneState.putString("incomingNumber",

+                                        incomingNumber);

+                                switch (state) {

+                                    case TelephonyManager.CALL_STATE_IDLE:

+                                        mPhoneState.putString("state", "idle");

+                                        break;

+                                    case TelephonyManager.CALL_STATE_OFFHOOK:

+                                        mPhoneState.putString("state", "offhook");

+                                        break;

+                                    case TelephonyManager.CALL_STATE_RINGING:

+                                        mPhoneState.putString("state", "ringing");

+                                        break;

+                                }

+                                mEventFacade.postEvent("phone",

+                                        mPhoneState.clone());

+                            }

+

+                            @Override

+                            public void onDataConnectionRealTimeInfoChanged(

+                                    DataConnectionRealTimeInfo dcRtInfo) {

+                                mModemPowerLevel.putString("Type", "modemPowerLvl");

+                                mModemPowerLevel.putLong("time", dcRtInfo.getTime());

+

+                                int state = dcRtInfo.getDcPowerState();

+                                if (POWER_STATE_LOW == state) {

+                                    mModemPowerLevel.putString("power_level", "LOW");

+                                } else if (POWER_STATE_MEDIUM == state) {

+                                    mModemPowerLevel.putString("power_level", "MEDIUM");

+                                } else if (POWER_STATE_HIGH == state) {

+                                    mModemPowerLevel.putString("power_level", "HIGH");

+                                } else {

+                                    mModemPowerLevel.putString("power_level", "UNKNOWN");

+                                }

+

+                                mEventFacade.postEvent("modemPowerLvl",

+                                        mModemPowerLevel.clone());

+                            }

+

+                            @Override

+                            public void onPreciseCallStateChanged(

+                                    PreciseCallState callState) {

+                                int foreGroundCallState = callState.getForegroundCallState();

+

+                                if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {

+                                    mPreciseCallState.putString("CallState", "ACTIVE");

+                                } else if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_HOLDING) {

+                                    mPreciseCallState.putString("CallState", "HOLDING)");

+                                } else if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_DIALING) {

+                                    mPreciseCallState.putString("CallState", "DIALING");

+                                } else if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_ALERTING) {

+                                    mPreciseCallState.putString("CallState", "ALERTING");

+                                } else if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_INCOMING) {

+                                    mPreciseCallState.putString("CallState", "INCOMING)");

+                                } else if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_WAITING) {

+                                    mPreciseCallState.putString("CallState", "WAITING");

+                                } else if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED) {

+                                    mPreciseCallState.putString("CallState", "DISCONNECTED");

+                                } else if (foreGroundCallState ==

+                                PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING) {

+                                    mPreciseCallState.putString("CallState", "DISCONNECTING");

+                                } else {

+                                    if (callState.getRingingCallState() ==

+                                    PreciseCallState.PRECISE_CALL_STATE_INCOMING) {

+                                        mPreciseCallState.putString("CallState", "INCOMING");

+                                    } else {

+                                        mPreciseCallState.putString("CallState", "IDLE");

+                                    }

+                                }

+                                mEventFacade.postEvent("PreciseCallState",

+                                        mPreciseCallState.clone());

+                            }

+

+                        };

+                    }

+                });

+    }

+

+    @Override

+    public void shutdown() {

+        stopTrackingPhoneState();

+    }

+

+    @Rpc(description = "Starts tracking phone state.")

+    @RpcStartEvent("phone")

+    public void startTrackingPhoneState() {

+        mTelephonyManager.listen(mPhoneStateListener,

+                PhoneStateListener.LISTEN_CALL_STATE |

+                        PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO |

+                        PhoneStateListener.LISTEN_PRECISE_CALL_STATE);

+    }

+

+    @Rpc(description = "Returns the current phone state and incoming number.",

+            returns = "A Map of \"state\" and \"incomingNumber\"")

+    public Bundle readPhoneState() {

+        return mPhoneState;

+    }

+

+    @Rpc(description = "Stops tracking phone state.")

+    @RpcStopEvent("phone")

+    public void stopTrackingPhoneState() {

+        mTelephonyManager.listen(mPhoneStateListener,

+                PhoneStateListener.LISTEN_NONE);

+    }

+

+    @Rpc(description = "Calls a contact/phone number by URI.")

+    public void phoneCall(@RpcParameter(name = "uri")

+    final String uriString)

+            throws Exception {

+        Uri uri = Uri.parse(uriString);

+        if (uri.getScheme().equals("content")) {

+            String phoneNumberColumn = PhonesColumns.NUMBER;

+            String selectWhere = null;

+            if ((FacadeManager.class.cast(mManager)).getSdkLevel() >= 5) {

+                Class<?> contactsContract_Data_class = Class

+                        .forName("android.provider.ContactsContract$Data");

+                Field RAW_CONTACT_ID_field = contactsContract_Data_class

+                        .getField("RAW_CONTACT_ID");

+                selectWhere = RAW_CONTACT_ID_field.get(null).toString() + "="

+                        + uri.getLastPathSegment();

+                Field CONTENT_URI_field = contactsContract_Data_class

+                        .getField("CONTENT_URI");

+                uri = Uri.parse(CONTENT_URI_field.get(null).toString());

+                Class<?> ContactsContract_CommonDataKinds_Phone_class = Class

+                        .forName("android.provider.ContactsContract$CommonDataKinds$Phone");

+                Field NUMBER_field = ContactsContract_CommonDataKinds_Phone_class

+                        .getField("NUMBER");

+                phoneNumberColumn = NUMBER_field.get(null).toString();

             }

-            mEventFacade.postEvent("phone", mPhoneState.clone());

-          }

-        };

-      }

-    });

-  }

-

-  @Override

-  public void shutdown() {

-    stopTrackingPhoneState();

-  }

-

-  @Rpc(description = "Starts tracking phone state.")

-  @RpcStartEvent("phone")

-  public void startTrackingPhoneState() {

-    mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

-  }

-

-  @Rpc(description = "Returns the current phone state and incoming number.", returns = "A Map of \"state\" and \"incomingNumber\"")

-  public Bundle readPhoneState() {

-    return mPhoneState;

-  }

-

-  @Rpc(description = "Stops tracking phone state.")

-  @RpcStopEvent("phone")

-  public void stopTrackingPhoneState() {

-    mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);

-  }

-

-  @Rpc(description = "Calls a contact/phone number by URI.")

-  public void phoneCall(@RpcParameter(name = "uri") final String uriString) throws Exception {

-    Uri uri = Uri.parse(uriString);

-    if (uri.getScheme().equals("content")) {

-      String phoneNumberColumn = PhonesColumns.NUMBER;

-      String selectWhere = null;

-      if ((FacadeManager.class.cast(mManager)).getSdkLevel() >= 5) {

-        Class<?> contactsContract_Data_class =

-            Class.forName("android.provider.ContactsContract$Data");

-        Field RAW_CONTACT_ID_field = contactsContract_Data_class.getField("RAW_CONTACT_ID");

-        selectWhere = RAW_CONTACT_ID_field.get(null).toString() + "=" + uri.getLastPathSegment();

-        Field CONTENT_URI_field = contactsContract_Data_class.getField("CONTENT_URI");

-        uri = Uri.parse(CONTENT_URI_field.get(null).toString());

-        Class<?> ContactsContract_CommonDataKinds_Phone_class =

-            Class.forName("android.provider.ContactsContract$CommonDataKinds$Phone");

-        Field NUMBER_field = ContactsContract_CommonDataKinds_Phone_class.getField("NUMBER");

-        phoneNumberColumn = NUMBER_field.get(null).toString();

-      }

-      ContentResolver resolver = mService.getContentResolver();

-      Cursor c = resolver.query(uri, new String[] { phoneNumberColumn }, selectWhere, null, null);

-      String number = "";

-      if (c.moveToFirst()) {

-        number = c.getString(c.getColumnIndexOrThrow(phoneNumberColumn));

-      }

-      c.close();

-      phoneCallNumber(number);

-    } else {

-      mAndroidFacade.startActivity(Intent.ACTION_CALL, uriString, null, null, null, null, null);

+            ContentResolver resolver = mService.getContentResolver();

+            Cursor c = resolver.query(uri, new String[] {

+                    phoneNumberColumn

+            },

+                    selectWhere, null, null);

+            String number = "";

+            if (c.moveToFirst()) {

+                number = c

+                        .getString(c.getColumnIndexOrThrow(phoneNumberColumn));

+            }

+            c.close();

+            phoneCallNumber(number);

+        } else {

+            mAndroidFacade.startActivity(Intent.ACTION_CALL, uriString, null,

+                    null, null, null, null);

+        }

     }

-  }

 

-  @Rpc(description = "Calls a phone number.")

-  public void phoneCallNumber(@RpcParameter(name = "phone number") final String number)

-      throws Exception {

-    phoneCall("tel:" + URLEncoder.encode(number, "ASCII"));

-  }

-

-  @Rpc(description = "Dials a contact/phone number by URI.")

-  public void phoneDial(@RpcParameter(name = "uri") final String uri) throws Exception {

-    mAndroidFacade.startActivity(Intent.ACTION_DIAL, uri, null, null, null, null, null);

-  }

-

-  @Rpc(description = "Dials a phone number.")

-  public void phoneDialNumber(@RpcParameter(name = "phone number") final String number)

-      throws Exception, UnsupportedEncodingException {

-    phoneDial("tel:" + URLEncoder.encode(number, "ASCII"));

-  }

-

-  @Rpc(description = "Returns the current cell location.")

-  public CellLocation getCellLocation() {

-    return mTelephonyManager.getCellLocation();

-  }

-

-  @Rpc(description = "Returns the numeric name (MCC+MNC) of current registered operator.")

-  public String getNetworkOperator() {

-    return mTelephonyManager.getNetworkOperator();

-  }

-

-  @Rpc(description = "Returns the alphabetic name of current registered operator.")

-  public String getNetworkOperatorName() {

-    return mTelephonyManager.getNetworkOperatorName();

-  }

-

-  @Rpc(description = "Returns a the radio technology (network type) currently in use on the device.")

-  public String getNetworkType() {

-    // TODO(damonkohler): API level 5 has many more types.

-    switch (mTelephonyManager.getNetworkType()) {

-    case TelephonyManager.NETWORK_TYPE_EDGE:

-      return "edge";

-    case TelephonyManager.NETWORK_TYPE_GPRS:

-      return "gprs";

-    case TelephonyManager.NETWORK_TYPE_UMTS:

-      return "umts";

-    case TelephonyManager.NETWORK_TYPE_UNKNOWN:

-      return "unknown";

-    default:

-      return null;

+    @Rpc(description = "Calls a phone number.")

+    public void phoneCallNumber(

+            @RpcParameter(name = "phone number")

+            final String number)

+            throws Exception {

+        phoneCall("tel:" + URLEncoder.encode(number, "ASCII"));

     }

-  }

 

-  @Rpc(description = "Returns the device phone type.")

-  public String getPhoneType() {

-    // TODO(damonkohler): API level 4 includes CDMA.

-    switch (mTelephonyManager.getPhoneType()) {

-    case TelephonyManager.PHONE_TYPE_GSM:

-      return "gsm";

-    case TelephonyManager.PHONE_TYPE_NONE:

-      return "none";

-    default:

-      return null;

+    @Rpc(description = "Dials a contact/phone number by URI.")

+    public void phoneDial(@RpcParameter(name = "uri")

+    final String uri)

+            throws Exception {

+        mAndroidFacade.startActivity(Intent.ACTION_DIAL, uri, null, null, null,

+                null, null);

     }

-  }

 

-  @Rpc(description = "Returns the ISO country code equivalent for the SIM provider's country code.")

-  public String getSimCountryIso() {

-    return mTelephonyManager.getSimCountryIso();

-  }

-

-  @Rpc(description = "Returns the MCC+MNC (mobile country code + mobile network code) of the provider of the SIM. 5 or 6 decimal digits.")

-  public String getSimOperator() {

-    return mTelephonyManager.getSimOperator();

-  }

-

-  @Rpc(description = "Returns the Service Provider Name (SPN).")

-  public String getSimOperatorName() {

-    return mTelephonyManager.getSimOperatorName();

-  }

-

-  @Rpc(description = "Returns the serial number of the SIM, if applicable. Return null if it is unavailable.")

-  public String getSimSerialNumber() {

-    return mTelephonyManager.getSimSerialNumber();

-  }

-

-  @Rpc(description = "Returns the state of the device SIM card.")

-  public String getSimState() {

-    switch (mTelephonyManager.getSimState()) {

-    case TelephonyManager.SIM_STATE_UNKNOWN:

-      return "uknown";

-    case TelephonyManager.SIM_STATE_ABSENT:

-      return "absent";

-    case TelephonyManager.SIM_STATE_PIN_REQUIRED:

-      return "pin_required";

-    case TelephonyManager.SIM_STATE_PUK_REQUIRED:

-      return "puk_required";

-    case TelephonyManager.SIM_STATE_NETWORK_LOCKED:

-      return "network_locked";

-    case TelephonyManager.SIM_STATE_READY:

-      return "ready";

-    default:

-      return null;

+    @Rpc(description = "Dials a phone number.")

+    public void phoneDialNumber(

+            @RpcParameter(name = "phone number")

+            final String number)

+            throws Exception, UnsupportedEncodingException {

+        phoneDial("tel:" + URLEncoder.encode(number, "ASCII"));

     }

-  }

 

-  @Rpc(description = "Returns the unique subscriber ID, for example, the IMSI for a GSM phone. Return null if it is unavailable.")

-  public String getSubscriberId() {

-    return mTelephonyManager.getSubscriberId();

-  }

+    @Rpc(description = "Returns the current cell location.")

+    public CellLocation getCellLocation() {

+        return mTelephonyManager.getCellLocation();

+    }

 

-  @Rpc(description = "Retrieves the alphabetic identifier associated with the voice mail number.")

-  public String getVoiceMailAlphaTag() {

-    return mTelephonyManager.getVoiceMailAlphaTag();

-  }

+    @Rpc(description = "Returns the numeric name (MCC+MNC) of current registered operator.")

+    public String getNetworkOperator() {

+        return mTelephonyManager.getNetworkOperator();

+    }

 

-  @Rpc(description = "Returns the voice mail number. Return null if it is unavailable.")

-  public String getVoiceMailNumber() {

-    return mTelephonyManager.getVoiceMailNumber();

-  }

+    @Rpc(description = "Returns the alphabetic name of current registered operator.")

+    public String getNetworkOperatorName() {

+        return mTelephonyManager.getNetworkOperatorName();

+    }

 

-  @Rpc(description = "Returns true if the device is considered roaming on the current network, for GSM purposes.")

-  public Boolean checkNetworkRoaming() {

-    return mTelephonyManager.isNetworkRoaming();

-  }

+    @Rpc(

+            description = "Returns a the radio technology (network type) currently in use on the device.")

+    public String getNetworkType() {

+        // TODO(damonkohler): API level 5 has many more types.

+        switch (mTelephonyManager.getNetworkType()) {

+            case TelephonyManager.NETWORK_TYPE_EDGE:

+                return "edge";

+            case TelephonyManager.NETWORK_TYPE_GPRS:

+                return "gprs";

+            case TelephonyManager.NETWORK_TYPE_UMTS:

+                return "umts";

+            case TelephonyManager.NETWORK_TYPE_UNKNOWN:

+                return "unknown";

+            default:

+                return null;

+        }

+    }

 

-  @Rpc(description = "Returns the unique device ID, for example, the IMEI for GSM and the MEID for CDMA phones. Return null if device ID is not available.")

-  public String getDeviceId() {

-    return mTelephonyManager.getDeviceId();

-  }

+    @Rpc(description = "Returns the device phone type.")

+    public String getPhoneType() {

+        // TODO(damonkohler): API level 4 includes CDMA.

+        switch (mTelephonyManager.getPhoneType()) {

+            case TelephonyManager.PHONE_TYPE_GSM:

+                return "gsm";

+            case TelephonyManager.PHONE_TYPE_NONE:

+                return "none";

+            default:

+                return null;

+        }

+    }

 

-  @Rpc(description = "Returns the software version number for the device, for example, the IMEI/SV for GSM phones. Return null if the software version is not available.")

-  public String getDeviceSoftwareVersion() {

-    return mTelephonyManager.getDeviceSoftwareVersion();

-  }

+    @Rpc(

+            description = "Returns the ISO country code equivalent for the SIM provider's country code.")

+    public String getSimCountryIso() {

+        return mTelephonyManager.getSimCountryIso();

+    }

 

-  @Rpc(description = "Returns the phone number string for line 1, for example, the MSISDN for a GSM phone. Return null if it is unavailable.")

-  public String getLine1Number() {

-    return mTelephonyManager.getLine1Number();

-  }

+    @Rpc(

+            description = "Returns the MCC+MNC (mobile country code + mobile network code) of the provider of the SIM. 5 or 6 decimal digits.")

+    public String getSimOperator() {

+        return mTelephonyManager.getSimOperator();

+    }

 

-  @Rpc(description = "Returns the neighboring cell information of the device.")

-  public List<NeighboringCellInfo> getNeighboringCellInfo() {

-    return mTelephonyManager.getNeighboringCellInfo();

-  }

+    @Rpc(description = "Returns the Service Provider Name (SPN).")

+    public String getSimOperatorName() {

+        return mTelephonyManager.getSimOperatorName();

+    }

+

+    @Rpc(

+            description = "Returns the serial number of the SIM, if applicable. Return null if it is unavailable.")

+    public String getSimSerialNumber() {

+        return mTelephonyManager.getSimSerialNumber();

+    }

+

+    @Rpc(description = "Returns the state of the device SIM card.")

+    public String getSimState() {

+        switch (mTelephonyManager.getSimState()) {

+            case TelephonyManager.SIM_STATE_UNKNOWN:

+                return "uknown";

+            case TelephonyManager.SIM_STATE_ABSENT:

+                return "absent";

+            case TelephonyManager.SIM_STATE_PIN_REQUIRED:

+                return "pin_required";

+            case TelephonyManager.SIM_STATE_PUK_REQUIRED:

+                return "puk_required";

+            case TelephonyManager.SIM_STATE_NETWORK_LOCKED:

+                return "network_locked";

+            case TelephonyManager.SIM_STATE_READY:

+                return "ready";

+            default:

+                return null;

+        }

+    }

+

+    @Rpc(

+            description = "Returns the unique subscriber ID, for example, the IMSI for a GSM phone. Return null if it is unavailable.")

+    public String getSubscriberId() {

+        return mTelephonyManager.getSubscriberId();

+    }

+

+    @Rpc(description = "Retrieves the alphabetic identifier associated with the voice mail number.")

+    public String getVoiceMailAlphaTag() {

+        return mTelephonyManager.getVoiceMailAlphaTag();

+    }

+

+    @Rpc(description = "Returns the voice mail number. Return null if it is unavailable.")

+    public String getVoiceMailNumber() {

+        return mTelephonyManager.getVoiceMailNumber();

+    }

+

+    @Rpc(

+            description = "Returns true if the device is considered roaming on the current network, for GSM purposes.")

+    public Boolean checkNetworkRoaming() {

+        return mTelephonyManager.isNetworkRoaming();

+    }

+

+    @Rpc(

+            description = "Returns the unique device ID, for example, the IMEI for GSM and the MEID for CDMA phones. Return null if device ID is not available.")

+    public String getDeviceId() {

+        return mTelephonyManager.getDeviceId();

+    }

+

+    @Rpc(

+            description = "Returns the software version number for the device, for example, the IMEI/SV for GSM phones. Return null if the software version is not available.")

+    public String getDeviceSoftwareVersion() {

+        return mTelephonyManager.getDeviceSoftwareVersion();

+    }

+

+    @Rpc(

+            description = "Returns the phone number string for line 1, for example, the MSISDN for a GSM phone. Return null if it is unavailable.")

+    public String getLine1Number() {

+        return mTelephonyManager.getLine1Number();

+    }

+

+    @Rpc(description = "Returns the neighboring cell information of the device.")

+    public List<NeighboringCellInfo> getNeighboringCellInfo() {

+        return mTelephonyManager.getNeighboringCellInfo();

+    }

+

+    @Rpc(description = "Checks the data connection state.",

+            returns = "True if data conenction is enabled.")

+    public Boolean checkDataConnection() {

+        return mConnect.getMobileDataEnabled();

+    }

+

+    @Rpc(description = "Toggles data connection on or off.")

+    public void toggleDataConnection(

+            @RpcParameter(name = "enabled")

+            @RpcOptional

+            Boolean enabled) {

+        if (enabled == null) {

+            enabled = !checkDataConnection();

+        }

+        mTelephonyManager.setDataEnabled(enabled);

+    }

+

+    @Rpc(description = "Sets an APN and make that as preferred APN.")

+    public void setAPN(

+            @RpcParameter(name = "name")

+            final String name,

+            @RpcParameter(name = "apn")

+            final String apn,

+            @RpcParameter(name = "type")

+            @RpcOptional

+            @RpcDefault("")

+            final String type) {

+        Uri uri;

+        Cursor cursor;

+

+        String mcc = "";

+        String mnc = "";

+

+        String numeric = SystemProperties.get(

+                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);

+        // MCC is first 3 chars and then in 2 - 3 chars of MNC

+        if (numeric != null && numeric.length() > 4) {

+            // Country code

+            mcc = numeric.substring(0, 3);

+            // Network code

+            mnc = numeric.substring(3);

+        }

+

+        uri = mService.getContentResolver().insert(

+                Telephony.Carriers.CONTENT_URI, new ContentValues());

+        if (uri == null) {

+            Log.w("Failed to insert new telephony provider into "

+                    + Telephony.Carriers.CONTENT_URI);

+            return;

+        }

+

+        cursor = mService.getContentResolver().query(uri, sProjection, null,

+                null, null);

+        cursor.moveToFirst();

+

+        ContentValues values = new ContentValues();

+

+        values.put(Telephony.Carriers.NAME, name);

+        values.put(Telephony.Carriers.APN, apn);

+        values.put(Telephony.Carriers.PROXY, "");

+        values.put(Telephony.Carriers.PORT, "");

+        values.put(Telephony.Carriers.MMSPROXY, "");

+        values.put(Telephony.Carriers.MMSPORT, "");

+        values.put(Telephony.Carriers.USER, "");

+        values.put(Telephony.Carriers.SERVER, "");

+        values.put(Telephony.Carriers.PASSWORD, "");

+        values.put(Telephony.Carriers.MMSC, "");

+        values.put(Telephony.Carriers.TYPE, type);

+        values.put(Telephony.Carriers.MCC, mcc);

+        values.put(Telephony.Carriers.MNC, mnc);

+        values.put(Telephony.Carriers.NUMERIC, mcc + mnc);

+

+        int ret = mService.getContentResolver().update(uri, values, null, null);

+        Log.d("after update " + ret);

+        cursor.close();

+

+        // Make this APN as the preferred

+        String where = "name=\"" + name + "\"";

+

+        Cursor c = mService.getContentResolver().query(

+                Telephony.Carriers.CONTENT_URI,

+                new String[] {

+                        "_id", "name", "apn", "type"

+                }, where, null,

+                Telephony.Carriers.DEFAULT_SORT_ORDER);

+        if (c != null) {

+            c.moveToFirst();

+            String key = c.getString(0);

+            final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";

+            ContentResolver resolver = mService.getContentResolver();

+            ContentValues prefAPN = new ContentValues();

+            prefAPN.put("apn_id", key);

+            resolver.update(Uri.parse(PREFERRED_APN_URI), prefAPN, null, null);

+        }

+        c.close();

+    }

+

+    @Rpc(description = "Returns the number of APNs defined")

+    public int getNumberOfAPNs() {

+        int noOfAPN = 0;

+        String where = "numeric=\""

+                + android.os.SystemProperties.get(

+                        TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "")

+                + "\"";

+

+        Cursor cursor = mService.getContentResolver().query(

+                Telephony.Carriers.CONTENT_URI,

+                new String[] {

+                        "_id", "name", "apn", "type"

+                }, where, null,

+                Telephony.Carriers.DEFAULT_SORT_ORDER);

+

+        if (cursor != null) {

+            noOfAPN = cursor.getCount();

+        }

+        cursor.close();

+        return noOfAPN;

+    }

+

+    @Rpc(description = "Returns the currently selected APN name")

+    public String getSelectedAPN() {

+        String key = null;

+        int ID_INDEX = 0;

+        final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";

+

+        Cursor cursor = mService.getContentResolver().query(

+                Uri.parse(PREFERRED_APN_URI), new String[] {

+                    "name"

+                }, null,

+                null, Telephony.Carriers.DEFAULT_SORT_ORDER);

+        if (cursor.getCount() > 0) {

+            cursor.moveToFirst();

+            key = cursor.getString(ID_INDEX);

+        }

+        cursor.close();

+        return key;

+    }

 }

diff --git a/ScriptingLayerForAndroid/AndroidManifest.xml b/ScriptingLayerForAndroid/AndroidManifest.xml
index ec2137b..eed2992 100644
--- a/ScriptingLayerForAndroid/AndroidManifest.xml
+++ b/ScriptingLayerForAndroid/AndroidManifest.xml
@@ -78,6 +78,8 @@
     <uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
     <uses-permission android:name="android.permission.REBOOT" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
     <uses-sdk android:targetSdkVersion="10" android:minSdkVersion="3" />
     <application android:icon="@drawable/sl4a_logo_48" android:label="@string/application_title" android:name=".Sl4aApplication">
         <activity android:name=".activity.ScriptManager" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="adjustResize" android:launchMode="singleTop">