am "Added Wifi Scanner automation test"

merged from partner/m-wireless-wifi-dev
27bb8ac Added Wifi Scanner automation test
diff --git a/Common/Android.mk b/Common/Android.mk
index cfe5c71..847b998 100644
--- a/Common/Android.mk
+++ b/Common/Android.mk
@@ -5,6 +5,7 @@
 
 
 LOCAL_MODULE := sl4a.Common
+LOCAL_MODULE_OWNER := google
 
 LOCAL_STATIC_JAVA_LIBRARIES := guava android-common sl4a.Utils libGoogleAnalytics
 LOCAL_JAVA_LIBRARIES := telephony-common
diff --git a/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java
index 2a4f6af..a030516 100644
--- a/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/ConnectivityManagerFacade.java
@@ -20,9 +20,11 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.provider.Settings.SettingNotFoundException;
+import android.os.Bundle;
 
 import com.googlecode.android_scripting.Log;
 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
@@ -43,25 +45,78 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
-                Log.d("Connectivity state changed.");
+
+            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+                Log.e("ConnectivityReceiver received non-connectivity action!");
+                return;
+            }
+
+            Bundle b = intent.getExtras();
+
+            if (b == null) {
+                Log.e("ConnectivityReceiver failed to receive extras!");
+                return;
+            }
+
+            int netType =
+                    b.getInt(ConnectivityManager.EXTRA_NETWORK_TYPE,
+                            ConnectivityManager.TYPE_NONE);
+
+            if(netType == ConnectivityManager.TYPE_NONE) {
+                Log.i("ConnectivityReceiver received change to TYPE_NONE.");
+                return;
+            }
+
+            /*
+             * Technically there is a race condition here, but
+             * retrieving the NetworkInfo from the bundle is deprecated.
+             * See ConnectivityManager.EXTRA_NETWORK_INFO
+            */
+            for (NetworkInfo info : mManager.getAllNetworkInfo()) {
+                if (info.getType() == netType) {
+                    mEventFacade.postEvent("onConnectivityChanged", info);
+                }
             }
         }
     }
 
-    private final ConnectivityManager mCon;
-
+    private final ConnectivityManager mManager;
     private final Service mService;
+    private final Context mContext;
+    private final ConnectivityReceiver mConnectivityReceiver;
+    private final EventFacade mEventFacade;
+    private boolean mTrackingConnectivityStateChange;
 
     public ConnectivityManagerFacade(FacadeManager manager) {
         super(manager);
         mService = manager.getService();
-        mCon = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mContext = mService.getBaseContext();
+        mManager = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mEventFacade = manager.getReceiver(EventFacade.class);
+        mConnectivityReceiver = new ConnectivityReceiver();
+        mTrackingConnectivityStateChange = false;
+    }
+
+    @Rpc(description = "Listen for connectivity changes")
+    public void startTrackingConnectivityStateChange() {
+        if( !mTrackingConnectivityStateChange) {
+            mTrackingConnectivityStateChange = true;
+            mContext.registerReceiver(mConnectivityReceiver,
+                    new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+        }
+    }
+
+    @Rpc(description = "Stop listening for connectivity changes")
+    public void stopTrackingConnectivityStateChange() {
+        if(mTrackingConnectivityStateChange) {
+            mTrackingConnectivityStateChange = false;
+            mContext.unregisterReceiver(mConnectivityReceiver);
+        }
     }
 
     @Rpc(description = "Get the extra information about the network state provided by lower network layers.")
     public String networkGetActiveConnectionExtraInfo() {
-        NetworkInfo current = mCon.getActiveNetworkInfo();
+        NetworkInfo current = mManager.getActiveNetworkInfo();
         if (current == null) {
             Log.d("No network is active at the moment.");
             return null;
@@ -71,7 +126,7 @@
 
     @Rpc(description = "Return the subtype name of the current network, null if not connected")
     public String networkGetActiveConnectionSubtypeName() {
-        NetworkInfo current = mCon.getActiveNetworkInfo();
+        NetworkInfo current = mManager.getActiveNetworkInfo();
         if (current == null) {
             Log.d("No network is active at the moment.");
             return null;
@@ -81,7 +136,7 @@
 
     @Rpc(description = "Return a human-readable name describe the type of the network, e.g. WIFI")
     public String networkGetActiveConnectionTypeName() {
-        NetworkInfo current = mCon.getActiveNetworkInfo();
+        NetworkInfo current = mManager.getActiveNetworkInfo();
         if (current == null) {
             Log.d("No network is active at the moment.");
             return null;
@@ -91,12 +146,12 @@
 
     @Rpc(description = "Get connection status information about all network types supported by the device.")
     public NetworkInfo[] networkGetAllInfo() {
-        return mCon.getAllNetworkInfo();
+        return mManager.getAllNetworkInfo();
     }
 
     @Rpc(description = "Check whether the active network is connected to the Internet.")
     public Boolean networkIsConnected() {
-        NetworkInfo current = mCon.getActiveNetworkInfo();
+        NetworkInfo current = mManager.getActiveNetworkInfo();
         if (current == null) {
             Log.d("No network is active at the moment.");
             return false;
@@ -121,10 +176,11 @@
         if (enabled == null) {
             enabled = !checkAirplaneMode();
         }
-        mCon.setAirplaneMode(enabled);
+        mManager.setAirplaneMode(enabled);
     }
 
     @Override
     public void shutdown() {
+        stopTrackingConnectivityStateChange();
     }
 }
diff --git a/Common/src/com/googlecode/android_scripting/facade/SmsFacade.java b/Common/src/com/googlecode/android_scripting/facade/SmsFacade.java
index 0bdd477..dcdd81d 100644
--- a/Common/src/com/googlecode/android_scripting/facade/SmsFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/SmsFacade.java
@@ -27,6 +27,12 @@
 import android.provider.Telephony.Sms.Intents;

 import android.telephony.SmsManager;

 import android.telephony.SmsMessage;

+import android.telephony.SmsCbMessage;

+import com.android.internal.telephony.gsm.SmsCbConstants;

+import com.android.internal.telephony.cdma.sms.SmsEnvelope;

+import android.telephony.SmsCbEtwsInfo;

+import android.telephony.SmsCbCmasInfo;

+import android.telephony.SubscriptionManager;

 

 import com.googlecode.android_scripting.Log;

 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;

@@ -56,6 +62,12 @@
     private Intent mSendIntent;

     private Intent mDeliveredIntent;

     private boolean mListeningIncomingSms;

+    private IntentFilter mEmergencyCBMessage;

+    private BroadcastReceiver mGsmEmergencyCBMessageListener;

+    private BroadcastReceiver mCdmaEmergencyCBMessageListener;

+    private boolean mGsmEmergencyCBListenerRegistered;

+    private boolean mCdmaEmergencyCBListenerRegistered;

+

 

     private static final String MESSAGE_STATUS_DELIVERED_ACTION =

             "com.googlecode.android_scripting.sms.MESSAGE_STATUS_DELIVERED";

@@ -63,10 +75,39 @@
             "com.googlecode.android_scripting.sms.MESSAGE_SENT";

     private static final String MESSAGE_RECEIVED_ACTION =

             "android.provider.Telephony.SMS_RECEIVED";

+    private static final String EMERGENCY_CB_MESSAGE_RECEIVED_ACTION=

+            "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";

     private final int MAX_MESSAGE_LENGTH = 160;

     private final int INTERNATIONAL_NUMBER_LENGTH = 12;

     private final int DOMESTIC_NUMBER_LENGTH = 10;

 

+    private final int[] mGsmCbMessageIdList = {

+        SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING,

+        SmsCbConstants.MESSAGE_ID_ETWS_TSUNAMI_WARNING,

+        SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING,

+        SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE ,

+        SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST,

+        SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE

+    };

+

+    private final int[] mCdmaCbMessageIdList = {

+            SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT,

+            SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT ,

+            SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT,

+            SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY ,

+            SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE

+        };

+

     public SmsFacade(FacadeManager manager) {

         super(manager);

         mService = manager.getService();

@@ -79,6 +120,10 @@
         mNumExpectedDeliveredEvents = 0;

         mNumReceivedDeliveredEvents = 0;

         mListeningIncomingSms=false;

+        mGsmEmergencyCBMessageListener = new SmsEmergencyCBMessageListener();

+        mCdmaEmergencyCBMessageListener = new SmsEmergencyCBMessageListener();

+        mGsmEmergencyCBListenerRegistered = false;

+        mCdmaEmergencyCBListenerRegistered = false;

 

         mSendIntent = new Intent(MESSAGE_SENT_ACTION);

         mDeliveredIntent = new Intent(MESSAGE_STATUS_DELIVERED_ACTION);

@@ -137,6 +182,63 @@
         return SmsManager.getDefault().getAllMessagesFromIcc();

     }

 

+    @Rpc(description = "Starts tracking GSM Emergency CB Messages.")

+    public void smsStartTrackingGsmEmergencyCBMessage() {

+        if(!mGsmEmergencyCBListenerRegistered) {

+            for (int messageId : mGsmCbMessageIdList) {

+                mSms.enableCellBroadcast(

+                     messageId,

+                     SmsManager.CELL_BROADCAST_RAN_TYPE_GSM);

+             }

+

+             mEmergencyCBMessage = new IntentFilter(EMERGENCY_CB_MESSAGE_RECEIVED_ACTION);

+             mService.registerReceiver(mGsmEmergencyCBMessageListener,

+                                       mEmergencyCBMessage);

+             mGsmEmergencyCBListenerRegistered = true;

+        }

+    }

+

+    @Rpc(description = "Stop tracking GSM Emergency CB Messages")

+    public void smsStopTrackingGsmEmergencyCBMessage() {

+        if(mGsmEmergencyCBListenerRegistered) {

+            mService.unregisterReceiver(mGsmEmergencyCBMessageListener);

+            mGsmEmergencyCBListenerRegistered = false;

+            for (int messageId : mGsmCbMessageIdList) {

+                mSms.disableCellBroadcast(

+                     messageId,

+                     SmsManager.CELL_BROADCAST_RAN_TYPE_GSM);

+            }

+        }

+    }

+

+    @Rpc(description = "Starts tracking CDMA Emergency CB Messages")

+    public void smsStartTrackingCdmaEmergencyCBMessage() {

+        if(!mCdmaEmergencyCBListenerRegistered) {

+            for (int messageId : mCdmaCbMessageIdList) {

+                mSms.enableCellBroadcast(

+                     messageId,

+                     SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA);

+            }

+            mEmergencyCBMessage = new IntentFilter(EMERGENCY_CB_MESSAGE_RECEIVED_ACTION);

+            mService.registerReceiver(mCdmaEmergencyCBMessageListener,

+                                      mEmergencyCBMessage);

+            mCdmaEmergencyCBListenerRegistered = true;

+        }

+    }

+

+    @Rpc(description = "Stop tracking CDMA Emergency CB Message.")

+    public void smsStopTrackingCdmaEmergencyCBMessage() {

+        if(mCdmaEmergencyCBListenerRegistered) {

+            mService.unregisterReceiver(mCdmaEmergencyCBMessageListener);

+            mCdmaEmergencyCBListenerRegistered = false;

+            for (int messageId : mCdmaCbMessageIdList) {

+                mSms.disableCellBroadcast(

+                     messageId,

+                     SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA);

+            }

+        }

+    }

+

     private class SmsSendListener extends BroadcastReceiver {

         @Override

         public void onReceive(Context context, Intent intent) {

@@ -205,6 +307,7 @@
             if (MESSAGE_RECEIVED_ACTION.equals(action)) {

                 Log.d("New SMS Received");

                 Bundle extras = intent.getExtras();

+                int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;

                 if (extras != null) {

                     Bundle event = new Bundle();

                     event.putString("Type", "NewSmsReceived");

@@ -220,6 +323,9 @@
                         smsMsg.append(sms.getMessageBody());

                     }

                     event.putString("Text", smsMsg.toString());

+                    // TODO

+                    // Need to explore how to get subId information.

+                    event.putInt("subscriptionId", subId);

                     mEventFacade.postEvent("onSmsReceived", event);

                 }

             }

@@ -244,11 +350,214 @@
         return senderNumberStr;

     }

 

+    private class SmsEmergencyCBMessageListener extends BroadcastReceiver {

+        @Override

+        public void onReceive(Context context, Intent intent) {

+            if (EMERGENCY_CB_MESSAGE_RECEIVED_ACTION.equals(intent.getAction())) {

+                Bundle extras = intent.getExtras();

+                if (extras != null) {

+                    Bundle event = new Bundle();

+                    String eventName = null;

+                    SmsCbMessage message = (SmsCbMessage) extras.get("message");

+                    if(message != null) {

+                        if(message.isEmergencyMessage()) {

+                            event.putString("geographicalScope", getGeographicalScope(

+                                             message.getGeographicalScope()));

+                            event.putInt("serialNumber", message.getSerialNumber());

+                            event.putString("location", message.getLocation().toString());

+                            event.putInt("serviceCategory", message.getServiceCategory());

+                            event.putString("language", message.getLanguageCode());

+                            event.putString("message", message.getMessageBody());

+                            event.putString("priority", getPriority(message.getMessagePriority()));

+                            if (message.isCmasMessage()) {

+                                // CMAS message

+                                eventName = "onCmasReceived";

+                                event.putString("cmasMessageClass", getCMASMessageClass(

+                                                 message.getCmasWarningInfo().getMessageClass()));

+                                event.putString("cmasCategory", getCMASCategory(

+                                                 message.getCmasWarningInfo().getCategory()));

+                                event.putString("cmasResponseType", getCMASResponseType(

+                                                 message.getCmasWarningInfo().getResponseType()));

+                                event.putString("cmasSeverity", getCMASSeverity(

+                                                 message.getCmasWarningInfo().getSeverity()));

+                                event.putString("cmasUrgency", getCMASUrgency(

+                                                 message.getCmasWarningInfo().getUrgency()));

+                                event.putString("cmasCertainty", getCMASCertainty(

+                                                message.getCmasWarningInfo().getCertainty()));

+                            } else if (message.isEtwsMessage()) {

+                                // ETWS message

+                                eventName = "onEtwsReceived";

+                                event.putString("etwsWarningType",getETWSWarningType(

+                                                 message.getEtwsWarningInfo().getWarningType()));

+                                event.putBoolean("etwsIsEmergencyUserAlert",

+                                                  message.getEtwsWarningInfo().isEmergencyUserAlert());

+                                event.putBoolean("etwsActivatePopup",

+                                                  message.getEtwsWarningInfo().isPopupAlert());

+                            } else {

+                                Log.d("Received message is not CMAS or ETWS");

+                            }

+                            if(eventName != null)

+                                mEventFacade.postEvent(eventName, event);

+                        }

+                    }

+                } else {

+                    Log.d("Received  Emergency CB without extras");

+                }

+            }

+        }

+    }

+

+    private static String getETWSWarningType(int type) {

+        switch(type) {

+            case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE:

+                return"EARTHQUAKE";

+            case SmsCbEtwsInfo.ETWS_WARNING_TYPE_TSUNAMI:

+                return "TSUNAMI";

+            case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI:

+                return "EARTHQUAKE_AND_TSUNAMI";

+            case SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE:

+                return "TEST_MESSAGE";

+            case SmsCbEtwsInfo.ETWS_WARNING_TYPE_OTHER_EMERGENCY:

+               return "OTHER_EMERGENCY";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getCMASMessageClass(int messageclass) {

+        switch(messageclass) {

+            case SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT:

+                return "PRESIDENTIAL_LEVEL_ALERT";

+            case SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT:

+                return "EXTREME_THREAT";

+            case SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT:

+                return "SEVERE_THREAT";

+            case SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY :

+                return "CHILD_ABDUCTION_EMERGENCY";

+            case SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST:

+                return "REQUIRED_MONTHLY_TEST";

+            case SmsCbCmasInfo.CMAS_CLASS_CMAS_EXERCISE :

+                return "CMAS_EXERCISE";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getCMASCategory(int category) {

+        switch(category) {

+            case SmsCbCmasInfo.CMAS_CATEGORY_GEO:

+                return "GEOPHYSICAL";

+            case SmsCbCmasInfo.CMAS_CATEGORY_MET:

+                return "METEOROLOGICAL";

+            case SmsCbCmasInfo.CMAS_CATEGORY_SAFETY:

+                return "SAFETY";

+            case SmsCbCmasInfo.CMAS_CATEGORY_SECURITY:

+                return "SECURITY";

+            case SmsCbCmasInfo.CMAS_CATEGORY_RESCUE:

+                return "RESCUE";

+            case SmsCbCmasInfo.CMAS_CATEGORY_FIRE:

+                return "FIRE";

+            case SmsCbCmasInfo.CMAS_CATEGORY_HEALTH:

+                return "HEALTH";

+            case SmsCbCmasInfo.CMAS_CATEGORY_ENV:

+                return "ENVIRONMENTAL";

+            case SmsCbCmasInfo.CMAS_CATEGORY_TRANSPORT:

+                return "TRANSPORTATION";

+            case SmsCbCmasInfo.CMAS_CATEGORY_INFRA:

+                return "INFRASTRUCTURE";

+            case SmsCbCmasInfo.CMAS_CATEGORY_CBRNE:

+                return "CHEMICAL";

+            case SmsCbCmasInfo.CMAS_CATEGORY_OTHER:

+                return "OTHER";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getCMASResponseType(int type) {

+        switch(type) {

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_SHELTER:

+                return "SHELTER";

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EVACUATE:

+                return "EVACUATE";

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_PREPARE:

+                return "PREPARE";

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EXECUTE:

+                return "EXECUTE";

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR:

+                return "MONITOR";

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_AVOID:

+                return "AVOID";

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_ASSESS:

+                return "ASSESS";

+            case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_NONE:

+                return "NONE";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getCMASSeverity(int severity) {

+        switch(severity) {

+            case SmsCbCmasInfo.CMAS_SEVERITY_EXTREME:

+                return "EXTREME";

+            case SmsCbCmasInfo.CMAS_SEVERITY_SEVERE:

+                return "SEVERE";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getCMASUrgency(int urgency) {

+        switch(urgency) {

+            case SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE:

+                return "IMMEDIATE";

+            case SmsCbCmasInfo.CMAS_URGENCY_EXPECTED:

+                return "EXPECTED";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getCMASCertainty(int certainty) {

+        switch(certainty) {

+            case SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED:

+                return "IMMEDIATE";

+            case SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY:

+                return "LIKELY";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getGeographicalScope(int scope) {

+        switch(scope) {

+            case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE:

+                return "CELL_WIDE_IMMEDIATE";

+            case SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE:

+                return "PLMN_WIDE ";

+            case SmsCbMessage.GEOGRAPHICAL_SCOPE_LA_WIDE :

+                return "LA_WIDE";

+            case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE:

+                return "CELL_WIDE";

+       }

+       return "UNKNOWN";

+    }

+

+    private static String getPriority(int priority) {

+        switch(priority) {

+            case SmsCbMessage.MESSAGE_PRIORITY_NORMAL:

+                return "NORMAL";

+            case SmsCbMessage.MESSAGE_PRIORITY_INTERACTIVE:

+                return "INTERACTIVE";

+            case SmsCbMessage.MESSAGE_PRIORITY_URGENT:

+                return "URGENT";

+            case SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY:

+                return "EMERGENCY";

+       }

+       return "UNKNOWN";

+    }

+

     @Override

     public void shutdown() {

       mService.unregisterReceiver(mSmsSendListener);

       if(mListeningIncomingSms) {

-              smsStopTrackingIncomingMessage();

+          smsStopTrackingIncomingMessage();

       }

+      smsStopTrackingGsmEmergencyCBMessage();

+      smsStopTrackingCdmaEmergencyCBMessage();

     }

 }

diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java
index 660eec2..2d5b37d 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothFacade.java
@@ -158,6 +158,12 @@
         return false;
     }
 
+    @Rpc(description = "Requests that the device be made connectable.")
+    public void bluetoothMakeConnectable() {
+        mBluetoothAdapter
+                .setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+    }
+
     @Rpc(description = "Requests that the device be discoverable for Bluetooth connections.")
     public void bluetoothMakeDiscoverable(
             @RpcParameter(name = "duration",
@@ -271,6 +277,7 @@
     @Rpc(description = "Start the remote device discovery process. ",
          returns = "true on success, false on error")
     public Boolean bluetoothStartDiscovery() {
+        DiscoveredDevices.clear();
         mService.registerReceiver(mDiscoveryReceiver, discoveryFilter);
         return mBluetoothAdapter.startDiscovery();
     }
diff --git a/Common/src/com/googlecode/android_scripting/facade/tele/ImsManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/tele/ImsManagerFacade.java
index 35879fd..5fa6490 100755
--- a/Common/src/com/googlecode/android_scripting/facade/tele/ImsManagerFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/tele/ImsManagerFacade.java
@@ -23,6 +23,7 @@
 
 import com.android.ims.ImsException;
 import com.android.ims.ImsManager;
+import com.android.ims.ImsConfig;
 import com.googlecode.android_scripting.Log;
 import com.googlecode.android_scripting.facade.FacadeManager;
 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
@@ -43,25 +44,119 @@
         mService = manager.getService();
         mContext = mService.getBaseContext();
         mImsManager = ImsManager.getInstance(mContext,
-                SubscriptionManager.getDefaultVoiceSubId());
+                SubscriptionManager.getDefaultVoicePhoneId());
     }
 
     @Rpc(description = "Return True if Enhanced 4g Lte mode is enabled by platform.")
     public boolean imsIsEnhanced4gLteModeSettingEnabledByPlatform() {
-        return ImsManager.isVolteEnabledByPlatform(mService);
+        return ImsManager.isVolteEnabledByPlatform(mContext);
     }
 
     @Rpc(description = "Return True if Enhanced 4g Lte mode is enabled by user.")
     public boolean imsIsEnhanced4gLteModeSettingEnabledByUser() {
-        return ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mService);
+        return ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mContext);
     }
 
     @Rpc(description = "Set Enhanced 4G mode.")
-    public void imsSetAdvanced4gMode(@RpcParameter(name = "enable") Boolean enable)
+    public void imsSetEnhanced4gMode(@RpcParameter(name = "enable") Boolean enable)
             throws ImsException{
         ImsManager.setEnhanced4gLteModeSetting(mService, enable);
     }
 
+    /**************************
+     * Begin WFC Calling APIs
+     **************************/
+
+    @Rpc(description = "Return True if WiFi Calling is enabled for platform.")
+    public boolean imsIsWfcEnabledByPlatform() {
+        return ImsManager.isWfcEnabledByPlatform(mContext);
+    }
+
+    @Rpc(description = "Set whether or not WFC is enabled during roaming")
+    public void imsSetWfcRoamingSetting(
+                        @RpcParameter(name = "enable")
+            Boolean enable) {
+        ImsManager.setWfcRoamingSetting(mContext, enable);
+
+    }
+
+    @Rpc(description = "Return True if WiFi Calling is enabled during roaming.")
+    public boolean imsIsWfcRoamingEnabledByUser() {
+        return ImsManager.isWfcRoamingEnabledByUser(mContext);
+    }
+
+    @Rpc(description = "Set the Wifi Calling Mode of operation")
+    public void imsSetWfcMode(
+                        @RpcParameter(name = "mode")
+            String mode)
+            throws IllegalArgumentException {
+
+        int mode_val;
+
+        switch (mode.toUpperCase()) {
+            case "WIFI_ONLY":
+                mode_val =
+                        ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY;
+                break;
+            case "CELLULAR_PREFERRED":
+                mode_val =
+                        ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
+                break;
+            case "WIFI_PREFERRED":
+                mode_val =
+                        ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED;
+                break;
+            case "DISABLED":
+                if (ImsManager.isWfcEnabledByPlatform(mContext) &&
+                        ImsManager.isWfcEnabledByUser(mContext) == true) {
+                    ImsManager.setWfcSetting(mContext, false);
+                }
+                return;
+            default:
+                throw new IllegalArgumentException("Invalid WfcMode");
+        }
+
+        ImsManager.setWfcMode(mContext, mode_val);
+        if (ImsManager.isWfcEnabledByPlatform(mContext) &&
+                ImsManager.isWfcEnabledByUser(mContext) == false) {
+            ImsManager.setWfcSetting(mContext, true);
+        }
+
+        return;
+    }
+
+    @Rpc(description = "Return current WFC Mode if Enabled.")
+    public String imsGetWfcMode() {
+        if(ImsManager.isWfcEnabledByUser(mContext) == false) {
+            return "DISABLED";
+        }
+       switch(ImsManager.getWfcMode(mContext)) {
+           case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
+               return "WIFI_PREFERRED";
+           case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
+               return "CELLULAR_PREFERRED";
+           case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
+               return "WIFI_ONLY";
+           default:
+               return "UNKNOWN";
+       }
+    }
+
+    @Rpc(description = "Return True if WiFi Calling is enabled by user.")
+    public boolean imsIsWfcEnabledByUser() {
+        return ImsManager.isWfcEnabledByUser(mContext);
+    }
+
+    @Rpc(description = "Set whether or not WFC is enabled")
+    public void imsSetWfcSetting(
+                        @RpcParameter(name = "enable")  Boolean enable) {
+        ImsManager.setWfcSetting(mContext,enable);
+    }
+
+    /**************************
+     * End WFC Calling APIs
+     **************************/
+
     @Override
     public void shutdown() {
 
diff --git a/Common/src/com/googlecode/android_scripting/facade/tele/PhoneFacade.java b/Common/src/com/googlecode/android_scripting/facade/tele/PhoneFacade.java
index 540b252..e2327d0 100755
--- a/Common/src/com/googlecode/android_scripting/facade/tele/PhoneFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/tele/PhoneFacade.java
@@ -27,8 +27,10 @@
 import android.telephony.CellLocation;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.provider.Telephony;
+import android.telephony.SubscriptionInfo;
 
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.RILConstants;
@@ -43,7 +45,7 @@
 import com.googlecode.android_scripting.facade.tele.TelephonyStateListeners
                                                    .CallStateChangeListener;
 import com.googlecode.android_scripting.facade.tele.TelephonyStateListeners
-                                                   .DataConnectionChangeListener;
+                                                   .DataConnectionRealTimeInfoChangeListener;
 import com.googlecode.android_scripting.facade.tele.TelephonyStateListeners
                                                    .DataConnectionStateChangeListener;
 import com.googlecode.android_scripting.facade.tele.TelephonyStateListeners
@@ -61,6 +63,7 @@
 import java.net.URLEncoder;
 import java.util.List;
 import java.util.concurrent.Callable;
+import java.util.HashMap;
 
 /**
  * Exposes TelephonyManager functionality.
@@ -75,13 +78,11 @@
     private final EventFacade mEventFacade;
     private final TelephonyManager mTelephonyManager;
 
-    private CallStateChangeListener mCallStateChangeListener;
-    private DataConnectionChangeListener mDataConnectionChangeListener;
-    private DataConnectionStateChangeListener mDataConnectionStateChangeListener;
-    private ServiceStateChangeListener mServiceStateChangeListener;
-
     private ITelephony mITelephony;
-    private PhoneStateListener mPhoneStateListener;
+    private final SubscriptionManager mSubscriptionManager;
+    private List<SubscriptionInfo> mSubInfos;
+    private HashMap<Integer, StateChangeListener> StateChangeListeners =
+                             new HashMap<Integer, StateChangeListener>();
 
     private static final String[] sProjection = new String[] {
             Telephony.Carriers._ID, // 0
@@ -115,152 +116,373 @@
                 (TelephonyManager) mService.getSystemService(Context.TELEPHONY_SERVICE);
         mAndroidFacade = manager.getReceiver(AndroidFacade.class);
         mEventFacade = manager.getReceiver(EventFacade.class);
+        mSubscriptionManager = SubscriptionManager.from(mService);
+        mSubInfos = mSubscriptionManager.getAllSubscriptionInfoList();
         MainThread.run(manager.getService(), new Callable<Object>() {
             @Override
             public Object call() throws Exception {
-                mCallStateChangeListener = new CallStateChangeListener(mEventFacade);
-                mDataConnectionChangeListener = new DataConnectionChangeListener(mEventFacade);
-                mDataConnectionStateChangeListener = new DataConnectionStateChangeListener(mEventFacade, mTelephonyManager);
-                mServiceStateChangeListener = new ServiceStateChangeListener(mEventFacade);
+                // Creating listeners for all subscription IDs
+                for (int i = 0; i < mSubInfos.size(); i++) {
+                    int subId = mSubInfos.get(i).getSubscriptionId();
+                    StateChangeListener mStateListeners =
+                                                     new StateChangeListener();
+                    mStateListeners.mServiceStateChangeListener =
+                        new ServiceStateChangeListener(mEventFacade, subId);
+                    mStateListeners.mDataConnectionStateChangeListener =
+                        new DataConnectionStateChangeListener(mEventFacade,
+                                                      mTelephonyManager, subId);
+                    mStateListeners.mCallStateChangeListener =
+                        new CallStateChangeListener(mEventFacade, subId);
+                    mStateListeners.mDataConnectionRTInfoChangeListener =
+                        new DataConnectionRealTimeInfoChangeListener(mEventFacade,
+                                                                     subId);
+
+                    StateChangeListeners.put(subId, mStateListeners);
+                }
                 return null;
             }
         });
     }
 
-    @Rpc(description = "Set preferred network setting.")
-    public boolean phoneSetPreferredNetworkType(String mode){
+    @Rpc(description = "Set preferred network setting " +
+                       "for default subscription ID")
+    public boolean phoneSetPreferredNetworkType(String mode) {
+        return phoneSetPreferredNetworkTypeForSubscription(mode,
+                                SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Set preferred network setting " +
+                       "for specified subscription ID")
+    public boolean phoneSetPreferredNetworkTypeForSubscription(String mode,
+                               @RpcParameter(name = "subId") Integer subId) {
         int networkType;
         int phoneType = mTelephonyManager.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
-            if (mode.equalsIgnoreCase("LTE")) {
-                networkType = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
-            } else if (mode.equalsIgnoreCase("Global")) {
-                networkType = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
-            } else if (mode.equalsIgnoreCase("3G")) {
-                networkType = RILConstants.NETWORK_MODE_WCDMA_PREF;
-            } else if (mode.equalsIgnoreCase("2G")) {
-                networkType = RILConstants.NETWORK_MODE_GSM_ONLY;
-            } else {
-                return false;
+            switch (mode.toUpperCase()) {
+                case "4G":
+                case "LTE":
+                    networkType = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
+                    break;
+                case "3G":
+                case "WCDMA":
+                    networkType = RILConstants.NETWORK_MODE_WCDMA_PREF;
+                    break;
+                case "2G":
+                case "GSM":
+                    networkType = RILConstants.NETWORK_MODE_GSM_ONLY;
+                    break;
+                case "GLOBAL":
+                    networkType =
+                            RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
+                    break;
+                default:
+                    return false;
             }
         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
-            if (mode.equalsIgnoreCase("LTE")) {
-                networkType = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
-            } else if (mode.equalsIgnoreCase("Global")) {
-                networkType = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
-            } else if (mode.equalsIgnoreCase("3G")) {
-                networkType = RILConstants.NETWORK_MODE_CDMA;
-            } else if (mode.equalsIgnoreCase("1X")) {
-                networkType = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
-            } else {
-                return false;
+            switch (mode.toUpperCase()) {
+                case "4G":
+                case "LTE":
+                    networkType = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
+                    break;
+                case "3G":
+                case "EVDO":
+                    networkType = RILConstants.NETWORK_MODE_CDMA;
+                    break;
+                case "2G":
+                case "1X":
+                    networkType = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
+                    break;
+                case "GLOBAL":
+                    networkType =
+                            RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
+                    break;
+                default:
+                    return false;
             }
-        } else{
+        } else {
             return false;
         }
-        Log.v("SL4A: Setting the preferred network setting to:" + networkType);
+        Log.v("SL4A: Setting the preferred network setting of subId: "
+                + subId +"to:" + networkType);
         mTelephonyManager.setPreferredNetworkType(networkType);
+        // TODO No framework API for setPreferredNetworkType(int subId)
+        // Need to find some other way to do this
         return true;
     }
 
-    @Rpc(description = "Get preferred network setting. Return value is integer.")
-    public int phoneGetPreferredNetworkTypeInteger(){
+    @Rpc(description = "Get preferred network setting for " +
+                       "default subscription ID .Return value is integer.")
+    public int phoneGetPreferredNetworkTypeInteger() {
+        return phoneGetPreferredNetworkTypeIntegerForSubscription(
+                                         SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Get preferred network setting for " +
+                       "specified subscription ID .Return value is integer.")
+    public int phoneGetPreferredNetworkTypeIntegerForSubscription(
+               @RpcParameter(name = "subId") Integer subId) {
+        // TODO No framework API for getPreferredNetworkType(int subId)
+        // Need to find some other way to do this
         return mTelephonyManager.getPreferredNetworkType();
     }
 
-    @Rpc(description = "Get preferred network setting. Return value is String.")
-    public String phoneGetPreferredNetworkTypeString(){
+    @Rpc(description = "Get preferred network setting for " +
+                       "default subscription ID.Return value is String.")
+    public String phoneGetPreferredNetworkType() {
+        return phoneGetPreferredNetworkTypeForSubscription(
+                                       SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Get preferred network setting for " +
+                       "specified subscription ID.Return value is String.")
+    public String phoneGetPreferredNetworkTypeForSubscription(
+            @RpcParameter(name = "subId") Integer subId) {
+        // TODO No framework API for getPreferredNetworkType(int subId)
+        // Need to find some other way to do this
         int mode = mTelephonyManager.getPreferredNetworkType();
         int phoneType = mTelephonyManager.getPhoneType();
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
-            if (mode == RILConstants.NETWORK_MODE_LTE_GSM_WCDMA){
-                return "LTE";
-            } else if (mode == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA){
-                return "Global";
-            } else if (mode == RILConstants.NETWORK_MODE_WCDMA_PREF) {
-                return "3G";
-            } else if (mode == RILConstants.NETWORK_MODE_GSM_ONLY) {
-                return "2G";
-            } else {
-                Log.d("Unknown mode in phone type GSM: " + mode);
+            switch (mode) {
+                case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
+                    return "LTE";
+                case RILConstants.NETWORK_MODE_WCDMA_PREF:
+                    return "WCDMA";
+                case RILConstants.NETWORK_MODE_GSM_ONLY:
+                    return "GSM";
+                case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
+                    return "GLOBAL";
+                default:
+                    Log.d("Unknown mode in phone type GSM: " + mode);
+                    return "UNKNOWN";
             }
-        } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA){
-            if (mode == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO){
-                return "LTE";
-            } else if (mode == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA){
-                return "Global";
-            } else if (mode == RILConstants.NETWORK_MODE_CDMA) {
-                return "3G";
-            } else if (mode == RILConstants.NETWORK_MODE_CDMA_NO_EVDO) {
-                return "1X";
-            } else {
-                Log.d("Unknown mode in phone type CDMA: " + mode);
+        } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+            switch (mode) {
+                case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
+                    return "LTE";
+                case RILConstants.NETWORK_MODE_CDMA:
+                    return "EVDO";
+                case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
+                    return "1X";
+                case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
+                    return "GLOBAL";
+                default:
+                    Log.d("Unknown mode in phone type CDMA: " + mode);
+                    return "UNKNOWN";
             }
         } else {
             Log.d("Unknown phone type: " + phoneType);
-        }
-        return null;
-    }
-
-    @Rpc(description = "Starts tracking call state change.")
-    public void phoneStartTrackingCallState() {
-        mTelephonyManager.listen(mCallStateChangeListener,
-                                   CallStateChangeListener.sListeningStates);
-    }
-
-    @Rpc(description = "Turn on/off precise listening on fore/background or ringing calls.")
-    public void phoneAdjustPreciseCallStateListenLevel(String type, Boolean listen) {
-        if (type.equals("Foreground")) {
-          mCallStateChangeListener.listenForeground = listen;
-        } else if (type.equals("Ringing")) {
-            mCallStateChangeListener.listenRinging = listen;
-        } else if (type.equals("Background")) {
-            mCallStateChangeListener.listenBackground = listen;
+            return null;
         }
     }
 
-    @Rpc(description = "Stops tracking call state change.")
-    public void phoneStopTrackingCallStateChange() {
-        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+    @Rpc(description = "Starts tracking call state change" +
+                       "for default subscription ID.")
+    public Boolean phoneStartTrackingCallState() {
+        return phoneStartTrackingCallStateForSubscription(
+                              SubscriptionManager.getDefaultVoiceSubId());
     }
 
-    @Rpc(description = "Starts tracking power level change.")
-    public void phoneStartTrackingPowerLevelChange() {
-        mTelephonyManager.listen(mDataConnectionChangeListener,
-                                 DataConnectionChangeListener.sListeningStates);
+    @Rpc(description = "Starts tracking call state change" +
+                       "for specified subscription ID.")
+    public Boolean phoneStartTrackingCallStateForSubscription(
+                @RpcParameter(name = "subId") Integer subId) {
+        try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mCallStateChangeListener,
+                CallStateChangeListener.sListeningStates);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
     }
 
-    @Rpc(description = "Stops tracking power level change.")
-    public void phoneStopTrackingPowerLevelChange() {
-        mTelephonyManager.listen(mDataConnectionChangeListener, PhoneStateListener.LISTEN_NONE);
+    @Rpc(description = "Turn on/off precise listening on fore/background or" +
+                       " ringing calls for default voice subscription ID.")
+    public Boolean phoneAdjustPreciseCallStateListenLevel(String type,
+                                                          Boolean listen) {
+        return phoneAdjustPreciseCallStateListenLevelForSubscription(type, listen,
+                                 SubscriptionManager.getDefaultVoiceSubId());
     }
 
-    @Rpc(description = "Starts tracking data connection state change.")
-    public void phoneStartTrackingDataConnectionStateChange() {
-        mTelephonyManager.listen(mDataConnectionStateChangeListener,
-                                 DataConnectionStateChangeListener.sListeningStates);
+    @Rpc(description = "Turn on/off precise listening on fore/background or" +
+                       " ringing calls for specified subscription ID.")
+    public Boolean phoneAdjustPreciseCallStateListenLevelForSubscription(String type,
+                   Boolean listen,
+                   @RpcParameter(name = "subId") Integer subId) {
+        try {
+            if (type.equals("Foreground")) {
+                StateChangeListeners.get(subId).mCallStateChangeListener.listenForeground = listen;
+            } else if (type.equals("Ringing")) {
+                StateChangeListeners.get(subId).mCallStateChangeListener.listenRinging = listen;
+            } else if (type.equals("Background")) {
+                StateChangeListeners.get(subId).mCallStateChangeListener.listenBackground = listen;
+            }
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
     }
 
-    @Rpc(description = "Stops tracking data connection state change.")
-    public void phoneStopTrackingDataConnectionStateChange() {
-        mTelephonyManager.listen(mDataConnectionStateChangeListener, PhoneStateListener.LISTEN_NONE);
+    @Rpc(description = "Stops tracking call state change " +
+            "for default voice subscription ID.")
+    public Boolean phoneStopTrackingCallStateChange() {
+        return phoneStopTrackingCallStateChangeForSubscription(
+                SubscriptionManager.getDefaultVoiceSubId());
     }
 
-    @Rpc(description = "Starts tracking service state change.")
-    public void phoneStartTrackingServiceStateChange() {
-        mTelephonyManager.listen(mServiceStateChangeListener,
-                                 ServiceStateChangeListener.sListeningStates);
+    @Rpc(description = "Stops tracking call state change " +
+                       "for specified subscription ID.")
+    public Boolean phoneStopTrackingCallStateChangeForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+        try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mCallStateChangeListener,
+                PhoneStateListener.LISTEN_NONE);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
     }
 
-    @Rpc(description = "Stops tracking service state change.")
-    public void phoneStopTrackingServiceStateChange() {
-        mTelephonyManager.listen(mServiceStateChangeListener, PhoneStateListener.LISTEN_NONE);
+    @Rpc(description = "Starts tracking data connection real time info change" +
+                       "for default subscription ID.")
+    public Boolean phoneStartTrackingDataConnectionRTInfoChange() {
+        return phoneStartTrackingDataConnectionRTInfoChangeForSubscription(
+                                 SubscriptionManager.getDefaultDataSubId());
+    }
+
+    @Rpc(description = "Starts tracking data connection real time info change" +
+                       "for specified subscription ID.")
+    public Boolean phoneStartTrackingDataConnectionRTInfoChangeForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+        try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mDataConnectionRTInfoChangeListener,
+                DataConnectionRealTimeInfoChangeListener.sListeningStates);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
+    }
+
+    @Rpc(description = "Stops tracking data connection real time info change" +
+                       "for default subscription ID.")
+    public Boolean phoneStopTrackingDataConnectionRTInfoChange() {
+        return phoneStopTrackingDataConnectionRTInfoChangeForSubscription(
+                                 SubscriptionManager.getDefaultDataSubId());
+    }
+
+    @Rpc(description = "Stops tracking data connection real time info change" +
+                       "for specified subscription ID.")
+    public Boolean phoneStopTrackingDataConnectionRTInfoChangeForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+        try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mDataConnectionRTInfoChangeListener,
+                PhoneStateListener.LISTEN_NONE);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
+    }
+
+    @Rpc(description = "Starts tracking data connection state change" +
+                       "for default subscription ID..")
+    public Boolean phoneStartTrackingDataConnectionStateChange() {
+        return phoneStartTrackingDataConnectionStateChangeForSubscription(
+                                 SubscriptionManager.getDefaultDataSubId());
+    }
+
+    @Rpc(description = "Starts tracking data connection state change" +
+                       "for specified subscription ID.")
+    public Boolean phoneStartTrackingDataConnectionStateChangeForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+        try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mDataConnectionStateChangeListener,
+                DataConnectionStateChangeListener.sListeningStates);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
+    }
+
+    @Rpc(description = "Stops tracking data connection state change " +
+                       "for default subscription ID..")
+    public Boolean phoneStopTrackingDataConnectionStateChange() {
+        return phoneStartTrackingDataConnectionStateChangeForSubscription(
+                                 SubscriptionManager.getDefaultDataSubId());
+    }
+
+    @Rpc(description = "Stops tracking data connection state change " +
+                       "for specified subscription ID..")
+    public Boolean phoneStopTrackingDataConnectionStateChangeForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+        try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mDataConnectionStateChangeListener,
+                PhoneStateListener.LISTEN_NONE);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
+    }
+
+    @Rpc(description = "Starts tracking service state change " +
+                       "for default subscription ID.")
+    public Boolean phoneStartTrackingServiceStateChange() {
+        return phoneStartTrackingServiceStateChangeForSubscription(
+                                 SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Starts tracking service state change " +
+                       "for specified subscription ID.")
+    public Boolean phoneStartTrackingServiceStateChangeForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+         try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mServiceStateChangeListener,
+                ServiceStateChangeListener.sListeningStates);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
+    }
+
+    @Rpc(description = "Stops tracking service state change " +
+                       "for default subscription ID.")
+    public Boolean phoneStopTrackingServiceStateChange() {
+        return phoneStartTrackingServiceStateChangeForSubscription(
+                                 SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Stops tracking service state change " +
+                       "for specified subscription ID.")
+    public Boolean phoneStopTrackingServiceStateChangeForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+        try {
+            mTelephonyManager.listen(
+                StateChangeListeners.get(subId).mServiceStateChangeListener,
+                PhoneStateListener.LISTEN_NONE);
+            return true;
+        } catch (Exception e) {
+            Log.e("Invalid subscription ID");
+            return false;
+        }
     }
 
     @Rpc(description = "Calls a contact/phone number by URI.")
     public void phoneCall(@RpcParameter(name = "uri")
-    final String uriString)
-            throws Exception {
+                final String uriString)
+                throws Exception {
         Uri uri = Uri.parse(uriString);
         if (uri.getScheme().equals("content")) {
             String phoneNumberColumn = ContactsContract.PhoneLookup.NUMBER;
@@ -312,8 +534,8 @@
             final String number)
             throws Exception {
         String uriString = "tel:" + URLEncoder.encode(number, "ASCII");
-        mAndroidFacade.startActivity(Intent.ACTION_CALL_PRIVILEGED, uriString, null,
-                                     null, null, null, null);
+        mAndroidFacade.startActivity(Intent.ACTION_CALL_PRIVILEGED, uriString,
+                                     null, null, null, null, null);
     }
 
     @Rpc(description = "Dials a contact/phone number by URI.")
@@ -342,14 +564,32 @@
         return mTelephonyManager.getCellLocation();
     }
 
-    @Rpc(description = "Returns the numeric name (MCC+MNC) of current registered operator.")
+    @Rpc(description = "Returns the numeric name (MCC+MNC) of registered operator." +
+                       "for default subscription ID")
     public String getNetworkOperator() {
-        return mTelephonyManager.getNetworkOperator();
+        return getNetworkOperatorForSubscription(
+                        SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns the alphabetic name of current registered operator.")
+    @Rpc(description = "Returns the numeric name (MCC+MNC) of registered operator" +
+                       "for specified subscription ID.")
+    public String getNetworkOperatorForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getNetworkOperatorForSubscription(subId);
+    }
+
+    @Rpc(description = "Returns the alphabetic name of current registered operator" +
+                       "for specified subscription ID.")
     public String getNetworkOperatorName() {
-        return mTelephonyManager.getNetworkOperatorName();
+        return getNetworkOperatorNameForSubscription(
+                        SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Returns the alphabetic name of registered operator " +
+                       "for specified subscription ID.")
+    public String getNetworkOperatorNameForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getNetworkOperatorName(subId);
     }
 
     private String getNetworkTypeString(int networkType) {
@@ -385,6 +625,12 @@
                 return "hspa";
             case TelephonyManager.NETWORK_TYPE_HSPAP:
                 return "hspap";
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                return "gsm";
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+                return "td_scdma";
+            case TelephonyManager.NETWORK_TYPE_IWLAN:
+                return "iwlan";
             case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                 return "unknown";
             default:
@@ -392,20 +638,22 @@
         }
     }
 
-    @Rpc(description = "Returns the current RAT in use on the device.")
+    @Rpc(description = "Returns the current RAT in use on the device.+" +
+                       "for default subscription ID")
     public String getNetworkType() {
 
         Log.d("sl4a:getNetworkType() is deprecated!" +
                 "Please use getVoiceNetworkType()" +
                 " or getDataNetworkTpe()");
 
-        return getNetworkTypeString(mTelephonyManager.getNetworkType());
+        return getNetworkTypeForSubscription(
+                       SubscriptionManager.getDefaultSubId());
     }
 
     @Rpc(description = "Returns the current RAT in use on the device" +
             " for a given Subscription.")
-    public String getNetworkTypeForSubscriber(
-            @RpcParameter(name = "subId") Integer subId) {
+    public String getNetworkTypeForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
 
         Log.d("sl4a:getNetworkTypeForSubscriber() is deprecated!" +
                 "Please use getVoiceNetworkType()" +
@@ -417,26 +665,28 @@
     @Rpc(description = "Returns the current voice RAT for" +
             " the default voice subscription.")
     public String getVoiceNetworkType() {
-        return getNetworkTypeString(mTelephonyManager.getVoiceNetworkType());
+        return getVoiceNetworkTypeForSubscription(
+                         SubscriptionManager.getDefaultVoiceSubId());
     }
 
     @Rpc(description = "Returns the current voice RAT for" +
-            " the chosen voice subscription.")
-    public String getVoiceNetworkTypeForSubscriber(
-            @RpcParameter(name = "subId") Integer subId) {
+            " the specified voice subscription.")
+    public String getVoiceNetworkTypeForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
         return getNetworkTypeString(mTelephonyManager.getVoiceNetworkType(subId));
     }
 
     @Rpc(description = "Returns the current data RAT for" +
             " the defaut data subscription")
     public String getDataNetworkType() {
-        return getNetworkTypeString(mTelephonyManager.getDataNetworkType());
+        return getDataNetworkTypeForSubscription(
+                         SubscriptionManager.getDefaultDataSubId());
     }
 
     @Rpc(description = "Returns the current data RAT for" +
-            " the defaut data subscription")
-    public String getDataNetworkTypeForSubscriber(
-            @RpcParameter(name = "subId") Integer subId) {
+            " the specified data subscription")
+    public String getDataNetworkTypeForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
         return getNetworkTypeString(mTelephonyManager.getDataNetworkType(subId));
     }
 
@@ -456,43 +706,68 @@
         }
     }
 
-    @Rpc(description = "Returns the MCC")
+    @Rpc(description = "Returns the MCC for default subscription ID")
     public String getSimCountryIso() {
-        return mTelephonyManager.getSimCountryIso();
+         return getSimCountryIsoForSubscription(
+                      SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns the MCC+MNC")
+    @Rpc(description = "Returns the MCC for specified subscription ID")
+    public String getSimCountryIsoForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getSimCountryIso(subId);
+    }
+
+    @Rpc(description = "Returns the MCC+MNC for default subscription ID")
     public String getSimOperator() {
-        return mTelephonyManager.getSimOperator();
+        return getSimOperatorForSubscription(
+                  SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns the MCC+MNC by subId")
-    public String getSimOperatorBySubId(
-            @RpcParameter(name = "subId")
-            Integer subId) {
+    @Rpc(description = "Returns the MCC+MNC for specified subscription ID")
+    public String getSimOperatorForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
         return mTelephonyManager.getSimOperator(subId);
     }
 
-    @Rpc(description = "Returns the Service Provider Name (SPN).")
+    @Rpc(description = "Returns the Service Provider Name (SPN)" +
+                       "for default subscription ID")
     public String getSimOperatorName() {
-        return mTelephonyManager.getSimOperatorName();
+        return getSimOperatorNameForSubscription(
+                  SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns the serial number of the SIM, or Null if unavailable")
+    @Rpc(description = "Returns the Service Provider Name (SPN)" +
+                       " for specified subscription ID.")
+    public String getSimOperatorNameForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getSimOperatorNameForSubscription(subId);
+    }
+
+    @Rpc(description = "Returns the serial number of the SIM for " +
+                       "default subscription ID, or Null if unavailable")
     public String getSimSerialNumber() {
-        return mTelephonyManager.getSimSerialNumber();
+        return getSimSerialNumberForSubscription(
+                  SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns the serial number of the SIM by SubId, or Null if unavailable")
-    public String getSimSerialNumberBySubId(
-            @RpcParameter(name = "subId")
-            Integer subId) {
+    @Rpc(description = "Returns the serial number of the SIM for " +
+                       "specified subscription ID, or Null if unavailable")
+    public String getSimSerialNumberForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
         return mTelephonyManager.getSimSerialNumber(subId);
     }
 
-    @Rpc(description = "Returns the state of the device SIM card.")
+    @Rpc(description = "Returns the state of the SIM card for default slot ID.")
     public String getSimState() {
-        switch (mTelephonyManager.getSimState()) {
+        return getSimStateForSlotId(
+                  mTelephonyManager.getDefaultSim());
+    }
+
+    @Rpc(description = "Returns the state of the SIM card for specified slot ID.")
+    public String getSimStateForSlotId(
+                  @RpcParameter(name = "slotId") Integer slotId) {
+        switch (mTelephonyManager.getSimState(slotId)) {
             case TelephonyManager.SIM_STATE_UNKNOWN:
                 return "uknown";
             case TelephonyManager.SIM_STATE_ABSENT:
@@ -510,53 +785,95 @@
         }
     }
 
-    @Rpc(description = "Returns the unique subscriber ID (such as IMSI), or null if unavailable")
+    @Rpc(description = "Returns the unique subscriber ID (such as IMSI) " +
+                       "for default subscription ID, or null if unavailable")
     public String getSubscriberId() {
-        return mTelephonyManager.getSubscriberId();
+        return getSubscriberIdForSubscription(
+                   SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Retrieves the alphabetic id associated with the voice mail number.")
+    @Rpc(description = "Returns the unique subscriber ID (such as IMSI) " +
+                       "for specified subscription ID, or null if unavailable")
+    public String getSubscriberIdForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getSubscriberId(subId);
+    }
+
+    @Rpc(description = "Retrieves the alphabetic id associated with the" +
+                       " voice mail number for default subscription ID.")
     public String getVoiceMailAlphaTag() {
-        return mTelephonyManager.getVoiceMailAlphaTag();
+        return getVoiceMailAlphaTagForSubscription(
+                   SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns the voice mail number; null if unavailable.")
+
+    @Rpc(description = "Retrieves the alphabetic id associated with the " +
+                       "voice mail number for specified subscription ID.")
+    public String getVoiceMailAlphaTagForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getVoiceMailAlphaTag(subId);
+    }
+
+    @Rpc(description = "Returns the voice mail number " +
+                       "for default subscription ID; null if unavailable.")
     public String getVoiceMailNumber() {
-        return mTelephonyManager.getVoiceMailNumber();
+        return getVoiceMailNumberForSubscription(
+                   SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns true if the device is in a roaming state")
+    @Rpc(description = "Returns the voice mail number " +
+                        "for specified subscription ID; null if unavailable.")
+    public String getVoiceMailNumberForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getVoiceMailNumber(subId);
+    }
+
+    @Rpc(description = "Returns true if the device is in  roaming state" +
+                       "for default subscription ID")
     public Boolean checkNetworkRoaming() {
-        return mTelephonyManager.isNetworkRoaming();
+        return checkNetworkRoamingForSubscription(
+                             SubscriptionManager.getDefaultSubId());
     }
 
-    @Rpc(description = "Returns true if the device is in a roaming state")
-    public Boolean checkNetworkRoamingBySubId(
-            @RpcParameter(name = "subId")
-            Integer subId){
+    @Rpc(description = "Returns true if the device is in roaming state " +
+                       "for specified subscription ID")
+    public Boolean checkNetworkRoamingForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
         return mTelephonyManager.isNetworkRoaming(subId);
     }
 
-    @Rpc(description = "Returns the unique device ID such as MEID or IMEI, null if unavailable")
+    @Rpc(description = "Returns the unique device ID such as MEID or IMEI " +
+                       "for deault sim slot ID, null if unavailable")
     public String getDeviceId() {
-        return mTelephonyManager.getDeviceId();
+        return getDeviceIdForSlotId(mTelephonyManager.getDefaultSim());
     }
 
-    @Rpc(description = "Returns the unique device ID such as MEID or IMEI by slotId, null if unavailable")
-    public String getDeviceIdBySlotId(
-            @RpcParameter(name = "slotId")
-            Integer slotId){
+    @Rpc(description = "Returns the unique device ID such as MEID or IMEI for" +
+                       " specified slot ID, null if unavailable")
+    public String getDeviceIdForSlotId(
+                  @RpcParameter(name = "slotId")
+                  Integer slotId){
         return mTelephonyManager.getDeviceId(slotId);
     }
 
-    @Rpc(description = "Returns the modem sw version, such as IMEI-SV; null if unavailable")
+    @Rpc(description = "Returns the modem sw version, such as IMEI-SV;" +
+                       " null if unavailable")
     public String getDeviceSoftwareVersion() {
         return mTelephonyManager.getDeviceSoftwareVersion();
     }
 
-    @Rpc(description = "Returns phone # string \"line 1\", such as MSISDN; null if unavailable")
+    @Rpc(description = "Returns phone # string \"line 1\", such as MSISDN " +
+                       "for default subscription ID; null if unavailable")
     public String getLine1Number() {
-        return mTelephonyManager.getLine1Number();
+        return getLine1NumberForSubscription(
+                        SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Returns phone # string \"line 1\", such as MSISDN " +
+                       "for specified subscription ID; null if unavailable")
+    public String getLine1NumberForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getLine1NumberForSubscriber(subId);
     }
 
     @Rpc(description = "Returns the neighboring cell information of the device.")
@@ -564,27 +881,47 @@
         return mTelephonyManager.getNeighboringCellInfo();
     }
 
-    @Rpc(description = "Returns True if data connection is enabled.")
-    public Boolean checkDataConnection() {
-        return mTelephonyManager.getDataEnabled();
+    @Rpc(description = "Returns True if cellular data is enabled for" +
+                       "default data subscription ID.")
+    public Boolean isDataEnabled() {
+        return isDataEnabledForSubscription(
+                   SubscriptionManager.getDefaultDataSubId());
     }
 
-    @Rpc(description = "Toggles data connection on or off.")
+    @Rpc(description = "Returns True if data connection is enabled.")
+    public Boolean isDataEnabledForSubscription(
+                   @RpcParameter(name = "subId") Integer subId) {
+        return mTelephonyManager.getDataEnabled(subId);
+    }
+
+    @Rpc(description = "Toggles data connection on /off for" +
+                       " default data subscription ID.")
     public void toggleDataConnection(
-            @RpcParameter(name = "enabled")
-            @RpcOptional
-            Boolean enabled) {
+                @RpcParameter(name = "enabled")
+                @RpcOptional Boolean enabled) {
+        toggleDataConnectionForSubscription(
+                         SubscriptionManager.getDefaultDataSubId(), enabled);
+    }
+
+    @Rpc(description = "Toggles data connection on/off for" +
+                       " specified subscription ID")
+    public void toggleDataConnectionForSubscription(
+                @RpcParameter(name = "subId") Integer subId,
+                @RpcParameter(name = "enabled")
+                @RpcOptional Boolean enabled) {
         if (enabled == null) {
-            enabled = !checkDataConnection();
+            enabled = !isDataEnabledForSubscription(subId);
         }
-        mTelephonyManager.setDataEnabled(enabled);
+        mTelephonyManager.setDataEnabled(subId, 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) {
+                       final String type,
+                       @RpcParameter(name = "subId") @RpcOptional Integer subId) {
+        //TODO Need to find out how to set APN for specific subId
         Uri uri;
         Cursor cursor;
 
@@ -653,7 +990,10 @@
     }
 
     @Rpc(description = "Returns the number of APNs defined")
-    public int getNumberOfAPNs() {
+    public int getNumberOfAPNs(
+               @RpcParameter(name = "subId")
+               @RpcOptional Integer subId) {
+        //TODO Need to find out how to get Number of APNs for specific subId
         int result = 0;
         String where = "numeric=\"" + android.os.SystemProperties.get(
                         TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "") + "\"";
@@ -671,7 +1011,10 @@
     }
 
     @Rpc(description = "Returns the currently selected APN name")
-    public String getSelectedAPN() {
+    public String getSelectedAPN(
+                  @RpcParameter(name = "subId")
+                  @RpcOptional Integer subId) {
+        //TODO Need to find out how to get selected APN for specific subId
         String key = null;
         int ID_INDEX = 0;
         final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";
@@ -713,11 +1056,65 @@
         }
     }
 
+    @Rpc(description = "Returns a boolean of isImsRegistered()")
+    public Boolean isImsRegistered() {
+        return mTelephonyManager.isImsRegistered();
+    }
+
+    @Rpc(description = "Returns the service state for default subscription ID")
+    public String getServiceState() {
+        // TODO
+        // No framework API available
+        return getServiceStateForSubscription(
+                                 SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Returns the service state for specified subscription ID")
+    public String getServiceStateForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        // TODO
+        // No framework API available
+        return null;
+    }
+
+    @Rpc(description = "Returns the call state for default subscription ID")
+    public String getCallState() {
+        return getCallStateForSubscription(
+                               SubscriptionManager.getDefaultSubId());
+    }
+
+    @Rpc(description = "Returns the call state for specified subscription ID")
+    public String getCallStateForSubscription(
+                  @RpcParameter(name = "subId") Integer subId) {
+        switch (mTelephonyManager.getCallState(subId)) {
+            case TelephonyManager.CALL_STATE_IDLE:
+                return "idle";
+            case TelephonyManager.CALL_STATE_RINGING:
+                return "ringing";
+            case TelephonyManager.CALL_STATE_OFFHOOK:
+                return "offhook";
+            default:
+                return null;
+        }
+    }
+
+    private static class StateChangeListener {
+        private ServiceStateChangeListener mServiceStateChangeListener;
+        private CallStateChangeListener mCallStateChangeListener;
+        private DataConnectionStateChangeListener
+                           mDataConnectionStateChangeListener;
+        private DataConnectionRealTimeInfoChangeListener
+                           mDataConnectionRTInfoChangeListener;
+    }
+
     @Override
     public void shutdown() {
-        phoneStopTrackingCallStateChange();
-        phoneStopTrackingPowerLevelChange();
-        phoneStopTrackingServiceStateChange();
-        phoneStopTrackingDataConnectionStateChange();
+        for (int i = 0; i < mSubInfos.size(); i++) {
+           int subId = mSubInfos.get(i).getSubscriptionId();
+           phoneStopTrackingCallStateChangeForSubscription(subId);
+           phoneStopTrackingDataConnectionRTInfoChangeForSubscription(subId);
+           phoneStopTrackingServiceStateChangeForSubscription(subId);
+           phoneStopTrackingDataConnectionStateChangeForSubscription(subId);
+        }
     }
 }
diff --git a/Common/src/com/googlecode/android_scripting/facade/tele/TelecomManagerFacade.java b/Common/src/com/googlecode/android_scripting/facade/tele/TelecomManagerFacade.java
index 2b805cd..f5dc5fd 100644
--- a/Common/src/com/googlecode/android_scripting/facade/tele/TelecomManagerFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/tele/TelecomManagerFacade.java
@@ -26,12 +26,14 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import com.googlecode.android_scripting.Log;
 import com.googlecode.android_scripting.facade.FacadeManager;
 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
 import com.googlecode.android_scripting.rpc.Rpc;
+import com.googlecode.android_scripting.rpc.RpcOptional;
 import com.googlecode.android_scripting.rpc.RpcParameter;
 
 /**
@@ -238,6 +240,40 @@
         InCallServiceImpl.mCalls.clear();
     }
 
+    @Rpc(description = "Get the state of a call according to call id.")
+    public String telecomCallGetState(
+            @RpcParameter(name = "callId")
+            String callId) {
+        Call call = InCallServiceImpl.mCalls.get(callId);
+        if (null == call){
+            Log.d("In telecomCallGetState, Invalid callId");
+            return "INVALID_ID";
+        }
+        int state = call.getState();
+        switch(state) {
+            case Call.STATE_NEW:
+                return "STATE_NEW";
+            case Call.STATE_DIALING:
+                return "STATE_DIALING";
+            case Call.STATE_RINGING:
+                return "STATE_RINGING";
+            case Call.STATE_HOLDING:
+                return "STATE_HOLDING";
+            case Call.STATE_ACTIVE:
+                return "STATE_ACTIVE";
+            case Call.STATE_DISCONNECTED:
+                return "STATE_DISCONNECTED";
+            case Call.STATE_PRE_DIAL_WAIT:
+                return "STATE_PRE_DIAL_WAIT";
+            case Call.STATE_CONNECTING:
+                return "STATE_CONNECTING";
+            case Call.STATE_DISCONNECTING:
+                return "STATE_DISCONNECTING";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
     @Rpc(description = "Sets the audio route (SPEAKER, BLUETOOTH, etc...).")
     public void telecomPhoneSetAudioRoute(
             @RpcParameter(name = "route")
@@ -270,4 +306,30 @@
     public void telecomSilenceRinger() {
         mTelecomManager.silenceRinger();
     }
+
+    @Rpc(description = "Swap two calls")
+    public void telecomSwapCalls() {
+        //TODO
+        // Swap the foreground and back ground calls
+    }
+
+    @Rpc(description = "Toggles call waiting feature on or off" +
+                       "for default voice subscription id.")
+    public void toggleCallWaiting(
+                @RpcParameter(name = "enabled")
+                @RpcOptional Boolean enabled) {
+        toggleCallWaitingForSubscription(
+              SubscriptionManager.getDefaultVoiceSubId(), enabled);
+    }
+
+    @Rpc(description = "Toggles call waiting feature on or off" +
+                       "for specified subscription id.")
+    public void toggleCallWaitingForSubscription(
+                @RpcParameter(name = "subId")
+                @RpcOptional Integer subId,
+                @RpcParameter(name = "enabled")
+                @RpcOptional Boolean enabled) {
+        //TODO
+        // Enable or Disable the call waiting feature
+    }
 }
diff --git a/Common/src/com/googlecode/android_scripting/facade/tele/TelephonyStateListeners.java b/Common/src/com/googlecode/android_scripting/facade/tele/TelephonyStateListeners.java
index 430760b..c080787 100644
--- a/Common/src/com/googlecode/android_scripting/facade/tele/TelephonyStateListeners.java
+++ b/Common/src/com/googlecode/android_scripting/facade/tele/TelephonyStateListeners.java
@@ -1,12 +1,14 @@
 package com.googlecode.android_scripting.facade.tele;
 
 import com.googlecode.android_scripting.facade.EventFacade;
+import com.googlecode.android_scripting.Log;
 import android.os.Bundle;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.PreciseCallState;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+import android.telephony.VoLteServiceState;
 
 /**
  * Store all subclasses of PhoneStateListener here.
@@ -89,7 +91,12 @@
             Bundle mCallStateEvent = new Bundle();
             String subEvent = null;
             String postIncomingNumberStr = null;
-            int len = incomingNumber.length();
+            int len = 0;
+            if (incomingNumber == null) {
+                len = 0;
+            } else {
+                len = incomingNumber.length();
+            }
             if (len > 0) {
                 /**
                  * Currently this incomingNumber modification is specific for US numbers.
@@ -114,6 +121,8 @@
                     subEvent = "Ringing";
                     break;
             }
+         // Need to change.using mSubId temporarily
+            mCallStateEvent.putInt("subscriptionId", mSubId);
             mEventFacade.postEvent("onCallStateChanged"+subEvent, mCallStateEvent);
         }
 
@@ -160,22 +169,24 @@
             } else if (newState == PreciseCallState.PRECISE_CALL_STATE_IDLE) {
                 subEvent = "Idle";
             }
+         // Need to change.using mSubId temporarily
+            EventMsg.putInt("subscriptionId", mSubId);
             mEventFacade.postEvent("onPreciseStateChanged"+subEvent, EventMsg);
         }
     }
 
-    public static class DataConnectionChangeListener extends PhoneStateListener {
+    public static class DataConnectionRealTimeInfoChangeListener extends PhoneStateListener {
 
         private final EventFacade mEventFacade;
         public static final int sListeningStates =
                 PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO;
 
-        public DataConnectionChangeListener(EventFacade ef) {
+        public DataConnectionRealTimeInfoChangeListener(EventFacade ef) {
             super();
             mEventFacade = ef;
         }
 
-        public DataConnectionChangeListener(EventFacade ef, int subId) {
+        public DataConnectionRealTimeInfoChangeListener(EventFacade ef, int subId) {
             super(subId);
             mEventFacade = ef;
         }
@@ -197,7 +208,9 @@
             } else if (state == DataConnectionRealTimeInfo.DC_POWER_STATE_UNKNOWN) {
                 subEvent = "Unknown";
             }
-            mEventFacade.postEvent("onModemPowerLevelChanged"+subEvent, event);
+         // Need to change.using mSubId temporarily
+            event.putInt("subscriptionId", mSubId);
+            mEventFacade.postEvent("onDataConnectionRealTimeInfoChanged"+subEvent, event);
         }
     }
 
@@ -241,6 +254,8 @@
                 subEvent = "UnknownStateCode";
                 event.putInt("UnknownStateCode", state);
             }
+         // Need to change.using mSubId temporarily
+            event.putInt("subscriptionId", mSubId);
             mEventFacade.postEvent("onDataConnectionStateChanged"+subEvent, event);
         }
     }
@@ -293,6 +308,8 @@
             event.putBoolean("isManualNwSelection", serviceState.getIsManualSelection());
             event.putBoolean("Roaming", serviceState.getRoaming());
             event.putBoolean("isEmergencyOnly", serviceState.isEmergencyOnly());
+            event.putInt("NetworkId", serviceState.getNetworkId());
+            event.putInt("SystemId", serviceState.getSystemId());
 
             if(subEvent.equals("InService")) {
                 switch(serviceState.getVoiceNetworkType()) {
@@ -308,8 +325,55 @@
                 }
             }
 
+            // Need to change.using mSubId temporarily
+            event.putInt("subscriptionId", mSubId);
+
             mEventFacade.postEvent("onServiceStateChanged"+subEvent, event);
         }
     }
 
+    public static class VolteServiceStateChangeListener
+            extends PhoneStateListener {
+
+        private final EventFacade mEventFacade;
+
+        public VolteServiceStateChangeListener(EventFacade ef) {
+            super();
+            mEventFacade = ef;
+        }
+
+        public VolteServiceStateChangeListener(EventFacade ef, int subId) {
+            super(subId);
+            mEventFacade = ef;
+        }
+
+        private static String getSrvccStateString(int srvccState) {
+            switch (srvccState) {
+                case VoLteServiceState.HANDOVER_STARTED:
+                    return "HANDOVER_STARTED";
+                case VoLteServiceState.HANDOVER_COMPLETED:
+                    return "HANDOVER_COMPLETED";
+                case VoLteServiceState.HANDOVER_FAILED:
+                    return "HANDOVER_FAILED";
+                case VoLteServiceState.HANDOVER_CANCELED:
+                    return "HANDOVER_CANCELED";
+                default:
+                    Log.e(String.format("getSrvccStateString():"
+                            + "unknown state %d", srvccState));
+                    return "UNKNOWN";
+            }
+        }
+
+        @Override
+        public void onVoLteServiceStateChanged(VoLteServiceState volteInfo) {
+            Bundle event = new Bundle();
+
+            event.putString("srvccState",
+                    getSrvccStateString(volteInfo.getSrvccState()));
+
+            mEventFacade.postEvent(
+                    "onVolteServiceStateChanged", event);
+        }
+    }
+
 }
diff --git a/Common/src/com/googlecode/android_scripting/facade/wifi/HttpFacade.java b/Common/src/com/googlecode/android_scripting/facade/wifi/HttpFacade.java
index 1b97685..5af51d7 100644
--- a/Common/src/com/googlecode/android_scripting/facade/wifi/HttpFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/wifi/HttpFacade.java
@@ -25,6 +25,7 @@
 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
 import com.googlecode.android_scripting.rpc.Rpc;
 import com.googlecode.android_scripting.rpc.RpcParameter;
+import com.googlecode.android_scripting.rpc.RpcOptional;
 
 /**
  * Basic http operations.
@@ -187,6 +188,34 @@
         mServerTimeout = timeout;
     }
 
+    @Rpc(description = "Ping to host, return success (true) or fail (false).")
+    // The optional timeout parameter is in unit of second.
+    public Boolean pingHost(@RpcParameter(name = "url") String urlString,
+            @RpcParameter(name = "timeout") @RpcOptional Integer timeout) {
+        Log.d("url:" + urlString);
+        try {
+            URL url = new URL(urlString);
+            String host = url.getHost();
+            Log.d("Host:" + host);
+            String pingCmdString = "ping -c 1 ";
+            if (timeout != null) {
+                pingCmdString = pingCmdString + "-W " + timeout + " ";
+            }
+            pingCmdString = pingCmdString + host;
+            Log.d("Execute command: " + pingCmdString);
+            Process p1 = java.lang.Runtime.getRuntime().exec(pingCmdString);
+            int returnVal = p1.waitFor();
+            boolean reachable = (returnVal == 0);
+            Log.d("Ping return Value:" + returnVal);
+            return reachable;
+        } catch (Exception e){
+            e.printStackTrace();
+            return false;
+        }
+        /*TODO see b/18899134 for more information.
+        */
+    }
+
     @Override
     public void shutdown() {
         for (int key : mSockets.keySet()) {
diff --git a/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java b/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java
index a487bf8..040c938 100644
--- a/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java
+++ b/Common/src/com/googlecode/android_scripting/jsonrpc/JsonBuilder.java
@@ -568,8 +568,8 @@
         JSONObject info = new JSONObject();
         info.put("isAvailable", data.isAvailable());
         info.put("isConnected", data.isConnected());
-        info.put("isConnected", data.isFailover());
-        info.put("isConnected", data.isRoaming());
+        info.put("isFailover", data.isFailover());
+        info.put("isRoaming", data.isRoaming());
         info.put("ExtraInfo", data.getExtraInfo());
         info.put("FailedReason", data.getReason());
         info.put("TypeName", data.getTypeName());
diff --git a/InterpreterForAndroid/Android.mk b/InterpreterForAndroid/Android.mk
index 56d12b5..9a28b75 100644
--- a/InterpreterForAndroid/Android.mk
+++ b/InterpreterForAndroid/Android.mk
@@ -5,6 +5,7 @@
 
 
 LOCAL_MODULE := sl4a.InterpreterForAndroid
+LOCAL_MODULE_OWNER := google
 LOCAL_STATIC_JAVA_LIBRARIES := guava android-common sl4a.Utils
 #LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4
 LOCAL_SRC_FILES := $(call all-java-files-under, src/com/googlecode/android_scripting)
diff --git a/QuickAction/Android.mk b/QuickAction/Android.mk
index 4cf3983..077f3ae 100644
--- a/QuickAction/Android.mk
+++ b/QuickAction/Android.mk
@@ -5,6 +5,7 @@
 
 
 LOCAL_MODULE := sl4a.QuickAction
+LOCAL_MODULE_OWNER := google
 LOCAL_STATIC_JAVA_LIBRARIES := guava android-common
 LOCAL_SRC_FILES := $(call all-java-files-under, src/net/londatiga/android)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/ScriptingLayer/Android.mk b/ScriptingLayer/Android.mk
index 8243822..c441f4c 100644
--- a/ScriptingLayer/Android.mk
+++ b/ScriptingLayer/Android.mk
@@ -5,7 +5,7 @@
 
 
 LOCAL_MODULE := sl4a.ScriptingLayer
-
+LOCAL_MODULE_OWNER := google
 
 LOCAL_STATIC_JAVA_LIBRARIES := guava android-common
 LOCAL_STATIC_JAVA_LIBRARIES += sl4a.Utils sl4a.Common
diff --git a/ScriptingLayerForAndroid/Android.mk b/ScriptingLayerForAndroid/Android.mk
index 63745b3..530d947 100644
--- a/ScriptingLayerForAndroid/Android.mk
+++ b/ScriptingLayerForAndroid/Android.mk
@@ -3,6 +3,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_PACKAGE_NAME := sl4a
+LOCAL_MODULE_OWNER := google
 
 LOCAL_CERTIFICATE := platform
 
diff --git a/ScriptingLayerForAndroid/AndroidManifest.xml b/ScriptingLayerForAndroid/AndroidManifest.xml
index 86e5b9f..50c5f34 100644
--- a/ScriptingLayerForAndroid/AndroidManifest.xml
+++ b/ScriptingLayerForAndroid/AndroidManifest.xml
@@ -93,6 +93,7 @@
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
+    <uses-permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
     <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">
diff --git a/Utils/Android.mk b/Utils/Android.mk
index fb0033f..babfa3a 100644
--- a/Utils/Android.mk
+++ b/Utils/Android.mk
@@ -5,6 +5,7 @@
 
 
 LOCAL_MODULE := sl4a.Utils
+LOCAL_MODULE_OWNER := google
 LOCAL_STATIC_JAVA_LIBRARIES := guava android-common
 LOCAL_SRC_FILES := $(call all-java-files-under, src)