Merge "Fixed old problems. Long values to String." into lmp-dev
diff --git a/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java b/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java
old mode 100644
new mode 100755
index 0c2889c..91394ad
--- a/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/PhoneFacade.java
@@ -1,578 +1,614 @@
-/*

- * Copyright (C) 2010 Google Inc.

- *

- * Licensed under the Apache License, Version 2.0 (the "License"); you may not

- * use this file except in compliance with the License. You may obtain a copy of

- * the License at

- *

- * http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

- * License for the specific language governing permissions and limitations under

- * the License.

- */

-

-package com.googlecode.android_scripting.facade;

-

-import android.app.Service;

-import android.content.ContentResolver;

-import android.content.Context;

-import android.content.Intent;

-import android.database.Cursor;

-import android.net.Uri;

-import android.os.Bundle;

-import android.provider.ContactsContract;

-import android.telephony.CellLocation;

-import android.telephony.NeighboringCellInfo;

-import android.telephony.PhoneStateListener;

-import android.telephony.TelephonyManager;

-import android.telephony.PreciseCallState;

-import android.net.ConnectivityManager;

-import android.provider.Telephony;

-import android.telephony.DataConnectionRealTimeInfo;

-

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

-

-import android.content.ContentValues;

-import android.os.SystemProperties;

-

-import com.googlecode.android_scripting.MainThread;

-import com.googlecode.android_scripting.jsonrpc.RpcReceiver;

-import com.googlecode.android_scripting.rpc.Rpc;

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

-import com.googlecode.android_scripting.rpc.RpcParameter;

-import com.googlecode.android_scripting.rpc.RpcStartEvent;

-import com.googlecode.android_scripting.rpc.RpcStopEvent;

-import com.googlecode.android_scripting.Log;

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

-

-import java.io.UnsupportedEncodingException;

-import java.lang.reflect.Field;

-import java.net.URLEncoder;

-import java.util.List;

-import java.util.concurrent.Callable;

-

-/**

- * Exposes TelephonyManager functionality.

- * 

- * @author Damon Kohler (damonkohler@gmail.com)

- * @author Felix Arends (felix.arends@gmail.com)

- */

-public class PhoneFacade extends RpcReceiver {

-

-    private final AndroidFacade mAndroidFacade;

-    private final EventFacade mEventFacade;

-    private final TelephonyManager mTelephonyManager;

-    private final Bundle mPhoneState;

-    private final Service mService;

-    private PhoneStateListener mPhoneStateListener;

-    private final ConnectivityManager mConnect;

-    private final Bundle mModemPowerLevel;

-    private final Bundle mPreciseCallState;

-

-    private final int POWER_STATE_LOW = 1;

-    private final int POWER_STATE_MEDIUM = 2;

-    private final int POWER_STATE_HIGH = 3;

-    private final int POWER_STATE_UNKNOWN = Integer.MAX_VALUE;

-

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

-            Telephony.Carriers._ID, // 0

-            Telephony.Carriers.NAME, // 1

-            Telephony.Carriers.APN, // 2

-            Telephony.Carriers.PROXY, // 3

-            Telephony.Carriers.PORT, // 4

-            Telephony.Carriers.USER, // 5

-            Telephony.Carriers.SERVER, // 6

-            Telephony.Carriers.PASSWORD, // 7

-            Telephony.Carriers.MMSC, // 8

-            Telephony.Carriers.MCC, // 9

-            Telephony.Carriers.MNC, // 10

-            Telephony.Carriers.NUMERIC, // 11

-            Telephony.Carriers.MMSPROXY,// 12

-            Telephony.Carriers.MMSPORT, // 13

-            Telephony.Carriers.AUTH_TYPE, // 14

-            Telephony.Carriers.TYPE, // 15

-            Telephony.Carriers.PROTOCOL, // 16

-            Telephony.Carriers.CARRIER_ENABLED, // 17

-            Telephony.Carriers.BEARER, // 18

-            Telephony.Carriers.ROAMING_PROTOCOL, // 19

-            Telephony.Carriers.MVNO_TYPE, // 20

-            Telephony.Carriers.MVNO_MATCH_DATA

-            // 21

-    };

-

-    public PhoneFacade(FacadeManager manager) {

-        super(manager);

-        mService = manager.getService();

-        mTelephonyManager = (TelephonyManager) mService

-                .getSystemService(Context.TELEPHONY_SERVICE);

-        mConnect = (ConnectivityManager) mService

-                .getSystemService(Context.CONNECTIVITY_SERVICE);

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

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

-        mPhoneState = new Bundle();

-        mModemPowerLevel = new Bundle();

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

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

-        mPreciseCallState = new Bundle();

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

-

-        mPhoneStateListener = MainThread.run(mService,

-                new Callable<PhoneStateListener>() {

-                    @Override

-                    public PhoneStateListener call() throws Exception {

-                        return new PhoneStateListener() {

-                            @Override

-                            public void onCallStateChanged(int state,

-                                    String incomingNumber) {

-                                mPhoneState.putString("incomingNumber",

-                                        incomingNumber);

-                                switch (state) {

-                                    case TelephonyManager.CALL_STATE_IDLE:

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

-                                        break;

-                                    case TelephonyManager.CALL_STATE_OFFHOOK:

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

-                                        break;

-                                    case TelephonyManager.CALL_STATE_RINGING:

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

-                                        break;

-                                }

-                                mEventFacade.postEvent("phone",

-                                        mPhoneState.clone());

-                            }

-

-                            @Override

-                            public void onDataConnectionRealTimeInfoChanged(

-                                    DataConnectionRealTimeInfo dcRtInfo) {

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

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

-

-                                int state = dcRtInfo.getDcPowerState();

-                                if (POWER_STATE_LOW == state) {

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

-                                } else if (POWER_STATE_MEDIUM == state) {

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

-                                } else if (POWER_STATE_HIGH == state) {

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

-                                } else {

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

-                                }

-

-                                mEventFacade.postEvent("modemPowerLvl",

-                                        mModemPowerLevel.clone());

-                            }

-

-                            @Override

-                            public void onPreciseCallStateChanged(

-                                    PreciseCallState callState) {

-                                int foreGroundCallState = callState.getForegroundCallState();

-

-                                if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {

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

-                                } else if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_HOLDING) {

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

-                                } else if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_DIALING) {

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

-                                } else if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_ALERTING) {

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

-                                } else if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_INCOMING) {

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

-                                } else if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_WAITING) {

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

-                                } else if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED) {

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

-                                } else if (foreGroundCallState ==

-                                PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING) {

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

-                                } else {

-                                    if (callState.getRingingCallState() ==

-                                    PreciseCallState.PRECISE_CALL_STATE_INCOMING) {

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

-                                    } else {

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

-                                    }

-                                }

-                                mEventFacade.postEvent("PreciseCallState",

-                                        mPreciseCallState.clone());

-                            }

-

-                        };

-                    }

-                });

-    }

-

-    @Override

-    public void shutdown() {

-        stopTrackingPhoneState();

-    }

-

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

-    @RpcStartEvent("phone")

-    public void startTrackingPhoneState() {

-        mTelephonyManager.listen(mPhoneStateListener,

-                PhoneStateListener.LISTEN_CALL_STATE |

-                        PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO |

-                        PhoneStateListener.LISTEN_PRECISE_CALL_STATE);

-    }

-

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

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

-    public Bundle readPhoneState() {

-        return mPhoneState;

-    }

-

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

-    @RpcStopEvent("phone")

-    public void stopTrackingPhoneState() {

-        mTelephonyManager.listen(mPhoneStateListener,

-                PhoneStateListener.LISTEN_NONE);

-    }

-

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

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

-    final String uriString)

-            throws Exception {

-        Uri uri = Uri.parse(uriString);

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

-            String phoneNumberColumn = ContactsContract.PhoneLookup.NUMBER;

-            String selectWhere = null;

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

-                Class<?> contactsContract_Data_class = Class

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

-                Field RAW_CONTACT_ID_field = contactsContract_Data_class

-                        .getField("RAW_CONTACT_ID");

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

-                        + uri.getLastPathSegment();

-                Field CONTENT_URI_field = contactsContract_Data_class

-                        .getField("CONTENT_URI");

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

-                Class<?> ContactsContract_CommonDataKinds_Phone_class = Class

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

-                Field NUMBER_field = ContactsContract_CommonDataKinds_Phone_class

-                        .getField("NUMBER");

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

-            }

-            ContentResolver resolver = mService.getContentResolver();

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

-                    phoneNumberColumn

-            },

-                    selectWhere, null, null);

-            String number = "";

-            if (c.moveToFirst()) {

-                number = c

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

-            }

-            c.close();

-            phoneCallNumber(number);

-        } else {

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

-                    null, null, null, null);

-        }

-    }

-

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

-    public void phoneCallNumber(

-            @RpcParameter(name = "phone number")

-            final String number)

-            throws Exception {

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

-    }

-

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

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

-    final String uri)

-            throws Exception {

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

-                null, null);

-    }

-

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

-    public void phoneDialNumber(

-            @RpcParameter(name = "phone number")

-            final String number)

-            throws Exception, UnsupportedEncodingException {

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

-    }

-

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

-    public CellLocation getCellLocation() {

-        return mTelephonyManager.getCellLocation();

-    }

-

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

-    public String getNetworkOperator() {

-        return mTelephonyManager.getNetworkOperator();

-    }

-

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

-    public String getNetworkOperatorName() {

-        return mTelephonyManager.getNetworkOperatorName();

-    }

-

-    @Rpc(

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

-    public String getNetworkType() {

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

-        switch (mTelephonyManager.getNetworkType()) {

-            case TelephonyManager.NETWORK_TYPE_EDGE:

-                return "edge";

-            case TelephonyManager.NETWORK_TYPE_GPRS:

-                return "gprs";

-            case TelephonyManager.NETWORK_TYPE_UMTS:

-                return "umts";

-            case TelephonyManager.NETWORK_TYPE_UNKNOWN:

-                return "unknown";

-            default:

-                return null;

-        }

-    }

-

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

-    public String getPhoneType() {

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

-        switch (mTelephonyManager.getPhoneType()) {

-            case TelephonyManager.PHONE_TYPE_GSM:

-                return "gsm";

-            case TelephonyManager.PHONE_TYPE_NONE:

-                return "none";

-            default:

-                return null;

-        }

-    }

-

-    @Rpc(

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

-    public String getSimCountryIso() {

-        return mTelephonyManager.getSimCountryIso();

-    }

-

-    @Rpc(

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

-    public String getSimOperator() {

-        return mTelephonyManager.getSimOperator();

-    }

-

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

-    public String getSimOperatorName() {

-        return mTelephonyManager.getSimOperatorName();

-    }

-

-    @Rpc(

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

-    public String getSimSerialNumber() {

-        return mTelephonyManager.getSimSerialNumber();

-    }

-

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

-    public String getSimState() {

-        switch (mTelephonyManager.getSimState()) {

-            case TelephonyManager.SIM_STATE_UNKNOWN:

-                return "uknown";

-            case TelephonyManager.SIM_STATE_ABSENT:

-                return "absent";

-            case TelephonyManager.SIM_STATE_PIN_REQUIRED:

-                return "pin_required";

-            case TelephonyManager.SIM_STATE_PUK_REQUIRED:

-                return "puk_required";

-            case TelephonyManager.SIM_STATE_NETWORK_LOCKED:

-                return "network_locked";

-            case TelephonyManager.SIM_STATE_READY:

-                return "ready";

-            default:

-                return null;

-        }

-    }

-

-    @Rpc(

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

-    public String getSubscriberId() {

-        return mTelephonyManager.getSubscriberId();

-    }

-

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

-    public String getVoiceMailAlphaTag() {

-        return mTelephonyManager.getVoiceMailAlphaTag();

-    }

-

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

-    public String getVoiceMailNumber() {

-        return mTelephonyManager.getVoiceMailNumber();

-    }

-

-    @Rpc(

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

-    public Boolean checkNetworkRoaming() {

-        return mTelephonyManager.isNetworkRoaming();

-    }

-

-    @Rpc(

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

-    public String getDeviceId() {

-        return mTelephonyManager.getDeviceId();

-    }

-

-    @Rpc(

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

-    public String getDeviceSoftwareVersion() {

-        return mTelephonyManager.getDeviceSoftwareVersion();

-    }

-

-    @Rpc(

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

-    public String getLine1Number() {

-        return mTelephonyManager.getLine1Number();

-    }

-

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

-    public List<NeighboringCellInfo> getNeighboringCellInfo() {

-        return mTelephonyManager.getNeighboringCellInfo();

-    }

-

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

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

-    public Boolean checkDataConnection() {

-        return mTelephonyManager.getDataEnabled();

-    }

-

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

-    public void toggleDataConnection(

-            @RpcParameter(name = "enabled")

-            @RpcOptional

-            Boolean enabled) {

-        if (enabled == null) {

-            enabled = !checkDataConnection();

-        }

-        mTelephonyManager.setDataEnabled(enabled);

-    }

-

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

-    public void setAPN(

-            @RpcParameter(name = "name")

-            final String name,

-            @RpcParameter(name = "apn")

-            final String apn,

-            @RpcParameter(name = "type")

-            @RpcOptional

-            @RpcDefault("")

-            final String type) {

-        Uri uri;

-        Cursor cursor;

-

-        String mcc = "";

-        String mnc = "";

-

-        String numeric = SystemProperties.get(

-                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);

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

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

-            // Country code

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

-            // Network code

-            mnc = numeric.substring(3);

-        }

-

-        uri = mService.getContentResolver().insert(

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

-        if (uri == null) {

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

-                    + Telephony.Carriers.CONTENT_URI);

-            return;

-        }

-

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

-                null, null);

-        cursor.moveToFirst();

-

-        ContentValues values = new ContentValues();

-

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

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

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

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

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

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

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

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

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

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

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

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

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

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

-

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

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

-        cursor.close();

-

-        // Make this APN as the preferred

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

-

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

-                Telephony.Carriers.CONTENT_URI,

-                new String[] {

-                        "_id", "name", "apn", "type"

-                }, where, null,

-                Telephony.Carriers.DEFAULT_SORT_ORDER);

-        if (c != null) {

-            c.moveToFirst();

-            String key = c.getString(0);

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

-            ContentResolver resolver = mService.getContentResolver();

-            ContentValues prefAPN = new ContentValues();

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

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

-        }

-        c.close();

-    }

-

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

-    public int getNumberOfAPNs() {

-        int noOfAPN = 0;

-        String where = "numeric=\""

-                + android.os.SystemProperties.get(

-                        TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "")

-                + "\"";

-

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

-                Telephony.Carriers.CONTENT_URI,

-                new String[] {

-                        "_id", "name", "apn", "type"

-                }, where, null,

-                Telephony.Carriers.DEFAULT_SORT_ORDER);

-

-        if (cursor != null) {

-            noOfAPN = cursor.getCount();

-        }

-        cursor.close();

-        return noOfAPN;

-    }

-

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

-    public String getSelectedAPN() {

-        String key = null;

-        int ID_INDEX = 0;

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

-

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

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

-                    "name"

-                }, null,

-                null, Telephony.Carriers.DEFAULT_SORT_ORDER);

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

-            cursor.moveToFirst();

-            key = cursor.getString(ID_INDEX);

-        }

-        cursor.close();

-        return key;

-    }

-}

+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.googlecode.android_scripting.facade;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.telephony.CellLocation;
+import android.telephony.NeighboringCellInfo;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.telephony.PreciseCallState;
+import android.net.ConnectivityManager;
+import android.provider.Telephony;
+import android.telephony.DataConnectionRealTimeInfo;
+
+import com.android.internal.telephony.TelephonyProperties;
+
+import android.content.ContentValues;
+import android.os.SystemProperties;
+
+import com.googlecode.android_scripting.MainThread;
+import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
+import com.googlecode.android_scripting.rpc.Rpc;
+import com.googlecode.android_scripting.rpc.RpcDefault;
+import com.googlecode.android_scripting.rpc.RpcParameter;
+import com.googlecode.android_scripting.Log;
+import com.googlecode.android_scripting.rpc.RpcOptional;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Exposes TelephonyManager functionality.
+ *
+ * @author Damon Kohler (damonkohler@gmail.com)
+ * @author Felix Arends (felix.arends@gmail.com)
+ */
+public class PhoneFacade extends RpcReceiver {
+
+    private final AndroidFacade mAndroidFacade;
+    private final EventFacade mEventFacade;
+    private final TelephonyManager mTelephonyManager;
+    private final Bundle mPhoneState;
+    private final Service mService;
+    private final Bundle mServiceState;
+    private PhoneStateListener mPhoneStateListener;
+    private final ConnectivityManager mConnect;
+    private final Bundle mModemPowerLevel;
+    private final Bundle mPreciseCallState;
+
+    private final int POWER_STATE_LOW = 1;
+    private final int POWER_STATE_MEDIUM = 2;
+    private final int POWER_STATE_HIGH = 3;
+    private final int POWER_STATE_UNKNOWN = Integer.MAX_VALUE;
+
+    private static final String[] sProjection = new String[] {
+            Telephony.Carriers._ID, // 0
+            Telephony.Carriers.NAME, // 1
+            Telephony.Carriers.APN, // 2
+            Telephony.Carriers.PROXY, // 3
+            Telephony.Carriers.PORT, // 4
+            Telephony.Carriers.USER, // 5
+            Telephony.Carriers.SERVER, // 6
+            Telephony.Carriers.PASSWORD, // 7
+            Telephony.Carriers.MMSC, // 8
+            Telephony.Carriers.MCC, // 9
+            Telephony.Carriers.MNC, // 10
+            Telephony.Carriers.NUMERIC, // 11
+            Telephony.Carriers.MMSPROXY,// 12
+            Telephony.Carriers.MMSPORT, // 13
+            Telephony.Carriers.AUTH_TYPE, // 14
+            Telephony.Carriers.TYPE, // 15
+            Telephony.Carriers.PROTOCOL, // 16
+            Telephony.Carriers.CARRIER_ENABLED, // 17
+            Telephony.Carriers.BEARER, // 18
+            Telephony.Carriers.ROAMING_PROTOCOL, // 19
+            Telephony.Carriers.MVNO_TYPE, // 20
+            Telephony.Carriers.MVNO_MATCH_DATA
+            // 21
+    };
+
+    public PhoneFacade(FacadeManager manager) {
+        super(manager);
+        mService = manager.getService();
+        mTelephonyManager =
+                (TelephonyManager) mService.getSystemService(Context.TELEPHONY_SERVICE);
+        mConnect =
+                (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mAndroidFacade = manager.getReceiver(AndroidFacade.class);
+        mEventFacade = manager.getReceiver(EventFacade.class);
+        mPhoneState = new Bundle();
+        mServiceState = new Bundle();
+        mModemPowerLevel = new Bundle();
+        mModemPowerLevel.putLong("time", 0);
+        mModemPowerLevel.putInt("power_level", POWER_STATE_UNKNOWN);
+        mPreciseCallState = new Bundle();
+        mPreciseCallState.putString("CallState", "");
+
+        mPhoneStateListener = MainThread.run(mService,
+                new Callable<PhoneStateListener>() {
+            @Override
+            public PhoneStateListener call() throws Exception {
+                return new PhoneStateListener() {
+                    @Override
+                    public void onCallStateChanged(int state,
+                            String incomingNumber) {
+                        mPhoneState.putString("incomingNumber",
+                                incomingNumber);
+                        switch (state) {
+                            case TelephonyManager.CALL_STATE_IDLE:
+                                mPhoneState.putString("state", "idle");
+                                break;
+                            case TelephonyManager.CALL_STATE_OFFHOOK:
+                                mPhoneState.putString("state", "offhook");
+                                break;
+                            case TelephonyManager.CALL_STATE_RINGING:
+                                mPhoneState.putString("state", "ringing");
+                                break;
+                        }
+                        mEventFacade.postEvent("PhoneCallStateChanged", mPhoneState.clone());
+                        mPhoneState.clear();
+                    }
+
+                    public void onServiceStateChanged(ServiceState serviceState) {
+                        switch(serviceState.getVoiceRegState()) {
+                            case ServiceState.STATE_EMERGENCY_ONLY:
+                                mServiceState.putString("serviceState", "emergency");
+                            break;
+                            case ServiceState.STATE_IN_SERVICE:
+                                mServiceState.putString("serviceState", "inService");
+                            break;
+                            case ServiceState.STATE_OUT_OF_SERVICE:
+                                mServiceState.putString("serviceState","noService");
+                            break;
+                            case ServiceState.STATE_POWER_OFF:
+                                mServiceState.putString("serviceState", "powerOff");
+                            break;
+                        }
+                        mServiceState.putString("operatorName",
+                                serviceState.getOperatorAlphaLong());
+                        mServiceState.putString("operatorCode",
+                                serviceState.getOperatorNumeric());
+                        mEventFacade.postEvent("PhoneServiceStateChanged", mPhoneState.clone());
+                        mPhoneState.clear();
+                    }
+
+                    @Override
+                    public void onDataConnectionRealTimeInfoChanged(
+                            DataConnectionRealTimeInfo dcRtInfo) {
+                        mModemPowerLevel.putString("Type", "modemPowerLvl");
+                        mModemPowerLevel.putLong("time", dcRtInfo.getTime());
+
+                        int state = dcRtInfo.getDcPowerState();
+                        if (POWER_STATE_LOW == state) {
+                            mModemPowerLevel.putString("power_level", "LOW");
+                        } else if (POWER_STATE_MEDIUM == state) {
+                            mModemPowerLevel.putString("power_level", "MEDIUM");
+                        } else if (POWER_STATE_HIGH == state) {
+                            mModemPowerLevel.putString("power_level", "HIGH");
+                        } else {
+                            mModemPowerLevel.putString("power_level", "UNKNOWN");
+                        }
+
+                        mEventFacade.postEvent("PhoneModemPowerLevelChanged",
+                                mModemPowerLevel.clone());
+                        mModemPowerLevel.clear();
+                    }
+
+                    @Override
+                    public void
+                    onPreciseCallStateChanged(PreciseCallState callState) {
+                        int foreGroundCallState = callState.getForegroundCallState();
+
+                        if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
+                            mPreciseCallState.putString("CallState", "ACTIVE");
+                        } else if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_HOLDING) {
+                            mPreciseCallState.putString("CallState", "HOLDING)");
+                        } else if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_DIALING) {
+                            mPreciseCallState.putString("CallState", "DIALING");
+                        } else if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_ALERTING) {
+                            mPreciseCallState.putString("CallState", "ALERTING");
+                        } else if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_INCOMING) {
+                            mPreciseCallState.putString("CallState", "INCOMING)");
+                        } else if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_WAITING) {
+                            mPreciseCallState.putString("CallState", "WAITING");
+                        } else if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED) {
+                            mPreciseCallState.putString("CallState", "DISCONNECTED");
+                        } else if (foreGroundCallState ==
+                                PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING) {
+                            mPreciseCallState.putString("CallState", "DISCONNECTING");
+                        } else {
+                            if (callState.getRingingCallState() ==
+                                    PreciseCallState.PRECISE_CALL_STATE_INCOMING) {
+                                mPreciseCallState.putString("CallState", "INCOMING");
+                            } else {
+                                mPreciseCallState.putString("CallState", "IDLE");
+                            }
+                        }
+                        mEventFacade.postEvent("PhonePreciseCallStateChanged",
+                                mPreciseCallState.clone());
+                        mPreciseCallState.clear();
+                    }
+
+                };
+            }
+        });
+    }
+
+    @Override
+    public void shutdown() {
+        stopTrackingPhoneState();
+    }
+
+    @Rpc(description = "Starts tracking phone state.")
+    public void startTrackingPhoneState() {
+        mTelephonyManager.listen(mPhoneStateListener,
+                PhoneStateListener.LISTEN_CALL_STATE
+                        | PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO
+                        | PhoneStateListener.LISTEN_PRECISE_CALL_STATE
+                        | PhoneStateListener.LISTEN_SERVICE_STATE);
+    }
+
+    @Rpc(description = "Returns the current phone state and incoming number.",
+            returns = "A Map of \"state\" and \"incomingNumber\"")
+    public Bundle readPhoneState() {
+        return mPhoneState;
+    }
+
+    @Rpc(description = "Stops tracking phone state.")
+    public void stopTrackingPhoneState() {
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+    }
+
+    @Rpc(description = "Calls a contact/phone number by URI.")
+    public void phoneCall(@RpcParameter(name = "uri")
+    final String uriString)
+            throws Exception {
+        Uri uri = Uri.parse(uriString);
+        if (uri.getScheme().equals("content")) {
+            String phoneNumberColumn = ContactsContract.PhoneLookup.NUMBER;
+            String selectWhere = null;
+            if ((FacadeManager.class.cast(mManager)).getSdkLevel() >= 5) {
+                Class<?> contactsContract_Data_class =
+                        Class.forName("android.provider.ContactsContract$Data");
+                Field RAW_CONTACT_ID_field =
+                        contactsContract_Data_class.getField("RAW_CONTACT_ID");
+                selectWhere = RAW_CONTACT_ID_field.get(null).toString() + "="
+                        + uri.getLastPathSegment();
+                Field CONTENT_URI_field =
+                        contactsContract_Data_class.getField("CONTENT_URI");
+                uri = Uri.parse(CONTENT_URI_field.get(null).toString());
+                Class<?> ContactsContract_CommonDataKinds_Phone_class =
+                        Class.forName("android.provider.ContactsContract$CommonDataKinds$Phone");
+                Field NUMBER_field =
+                        ContactsContract_CommonDataKinds_Phone_class.getField("NUMBER");
+                phoneNumberColumn = NUMBER_field.get(null).toString();
+            }
+            ContentResolver resolver = mService.getContentResolver();
+            Cursor c = resolver.query(uri, new String[] {
+                    phoneNumberColumn
+            },
+                    selectWhere, null, null);
+            String number = "";
+            if (c.moveToFirst()) {
+                number = c.getString(c.getColumnIndexOrThrow(phoneNumberColumn));
+            }
+            c.close();
+            phoneCallNumber(number);
+        } else {
+            mAndroidFacade.startActivity(Intent.ACTION_CALL, uriString, null,
+                    null, null, null, null);
+        }
+    }
+
+    @Rpc(description = "Calls a phone number.")
+    public void phoneCallNumber(
+            @RpcParameter(name = "phone number")
+            final String number)
+            throws Exception {
+        phoneCall("tel:" + URLEncoder.encode(number, "ASCII"));
+    }
+
+    @Rpc(description = "Dials a contact/phone number by URI.")
+    public void phoneDial(@RpcParameter(name = "uri")
+    final String uri)
+            throws Exception {
+        mAndroidFacade.startActivity(Intent.ACTION_DIAL, uri, null, null, null,
+                null, null);
+    }
+
+    @Rpc(description = "Dials a phone number.")
+    public void phoneDialNumber(@RpcParameter(name = "phone number")
+    final String number)
+            throws Exception, UnsupportedEncodingException {
+        phoneDial("tel:" + URLEncoder.encode(number, "ASCII"));
+    }
+
+    @Rpc(description = "Returns the current cell location.")
+    public CellLocation getCellLocation() {
+        return mTelephonyManager.getCellLocation();
+    }
+
+    @Rpc(description = "Returns the numeric name (MCC+MNC) of current registered operator.")
+    public String getNetworkOperator() {
+        return mTelephonyManager.getNetworkOperator();
+    }
+
+    @Rpc(description = "Returns the alphabetic name of current registered operator.")
+    public String getNetworkOperatorName() {
+        return mTelephonyManager.getNetworkOperatorName();
+    }
+
+    @Rpc(description = "Returns the current RAT in use on the device.")
+    public String getNetworkType() {
+        // TODO(damonkohler): API level 5 has many more types.
+        switch (mTelephonyManager.getNetworkType()) {
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+                return "edge";
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+                return "gprs";
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+                return "umts";
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+                return "hsdpa";
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+                return "hsupa";
+            case TelephonyManager.NETWORK_TYPE_CDMA:
+                return "cdma";
+            case TelephonyManager.NETWORK_TYPE_EVDO_0:
+                return "evdo_0";
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:
+                return "evdo_a";
+            case TelephonyManager.NETWORK_TYPE_EVDO_B:
+                return "evdo_b";
+            case TelephonyManager.NETWORK_TYPE_1xRTT:
+                return "1xrtt";
+            case TelephonyManager.NETWORK_TYPE_IDEN:
+                return "iden";
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                return "lte";
+            case TelephonyManager.NETWORK_TYPE_EHRPD:
+                return "ehrpd";
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+                return "hspap";
+            case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+                return "unknown";
+            default:
+                return null;
+        }
+    }
+
+    @Rpc(description = "Returns the device phone type.")
+    public String getPhoneType() {
+        switch (mTelephonyManager.getPhoneType()) {
+            case TelephonyManager.PHONE_TYPE_GSM:
+                return "gsm";
+            case TelephonyManager.PHONE_TYPE_NONE:
+                return "none";
+            case TelephonyManager.PHONE_TYPE_CDMA:
+                return "none";
+            case TelephonyManager.PHONE_TYPE_SIP:
+                return "none";
+            default:
+                return null;
+        }
+    }
+
+    @Rpc(description = "Returns the MCC")
+    public String getSimCountryIso() {
+        return mTelephonyManager.getSimCountryIso();
+    }
+
+    @Rpc(description = "Returns the MCC+MNC")
+    public String getSimOperator() {
+        return mTelephonyManager.getSimOperator();
+    }
+
+    @Rpc(description = "Returns the Service Provider Name (SPN).")
+    public String getSimOperatorName() {
+        return mTelephonyManager.getSimOperatorName();
+    }
+
+    @Rpc(description = "Returns the serial number of the SIM, or Null if unavailable")
+    public String getSimSerialNumber() {
+        return mTelephonyManager.getSimSerialNumber();
+    }
+
+    @Rpc(description = "Returns the state of the device SIM card.")
+    public String getSimState() {
+        switch (mTelephonyManager.getSimState()) {
+            case TelephonyManager.SIM_STATE_UNKNOWN:
+                return "uknown";
+            case TelephonyManager.SIM_STATE_ABSENT:
+                return "absent";
+            case TelephonyManager.SIM_STATE_PIN_REQUIRED:
+                return "pin_required";
+            case TelephonyManager.SIM_STATE_PUK_REQUIRED:
+                return "puk_required";
+            case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
+                return "network_locked";
+            case TelephonyManager.SIM_STATE_READY:
+                return "ready";
+            default:
+                return null;
+        }
+    }
+
+    @Rpc(description = "Returns the unique subscriber ID (such as IMSI), or null if unavailable")
+    public String getSubscriberId() {
+        return mTelephonyManager.getSubscriberId();
+    }
+
+    @Rpc(description = "Retrieves the alphabetic id associated with the voice mail number.")
+    public String getVoiceMailAlphaTag() {
+        return mTelephonyManager.getVoiceMailAlphaTag();
+    }
+
+    @Rpc(description = "Returns the voice mail number; null if unavailable.")
+    public String getVoiceMailNumber() {
+        return mTelephonyManager.getVoiceMailNumber();
+    }
+
+    @Rpc(description = "Returns true if the device is in a roaming state")
+    public Boolean checkNetworkRoaming() {
+        return mTelephonyManager.isNetworkRoaming();
+    }
+
+    @Rpc(description = "Returns the unique device ID such as MEID or IMEI, null if unavailable")
+    public String getDeviceId() {
+        return mTelephonyManager.getDeviceId();
+    }
+
+    @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")
+    public String getLine1Number() {
+        return mTelephonyManager.getLine1Number();
+    }
+
+    @Rpc(description = "Returns the neighboring cell information of the device.")
+    public List<NeighboringCellInfo> getNeighboringCellInfo() {
+        return mTelephonyManager.getNeighboringCellInfo();
+    }
+
+    @Rpc(description = "Returns True if data connection is enabled.")
+    public Boolean checkDataConnection() {
+        return mTelephonyManager.getDataEnabled();
+    }
+
+    @Rpc(description = "Toggles data connection on or off.")
+    public void toggleDataConnection(
+            @RpcParameter(name = "enabled")
+            @RpcOptional
+            Boolean enabled) {
+        if (enabled == null) {
+            enabled = !checkDataConnection();
+        }
+        mTelephonyManager.setDataEnabled(enabled);
+    }
+
+    @Rpc(description = "Sets an APN and make that as preferred APN.")
+    public void setAPN(
+            @RpcParameter(name = "name")
+            final String name,
+            @RpcParameter(name = "apn")
+            final String apn,
+            @RpcParameter(name = "type")
+            @RpcOptional
+            @RpcDefault("")
+            final String type) {
+        Uri uri;
+        Cursor cursor;
+
+        String mcc = "";
+        String mnc = "";
+
+        String numeric = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
+        // MCC is first 3 chars and then in 2 - 3 chars of MNC
+        if (numeric != null && numeric.length() > 4) {
+            // Country code
+            mcc = numeric.substring(0, 3);
+            // Network code
+            mnc = numeric.substring(3);
+        }
+
+        uri = mService.getContentResolver().insert(
+                Telephony.Carriers.CONTENT_URI, new ContentValues());
+        if (uri == null) {
+            Log.w("Failed to insert new telephony provider into "
+                    + Telephony.Carriers.CONTENT_URI);
+            return;
+        }
+
+        cursor = mService.getContentResolver().query(uri, sProjection, null,
+                null, null);
+        cursor.moveToFirst();
+
+        ContentValues values = new ContentValues();
+
+        values.put(Telephony.Carriers.NAME, name);
+        values.put(Telephony.Carriers.APN, apn);
+        values.put(Telephony.Carriers.PROXY, "");
+        values.put(Telephony.Carriers.PORT, "");
+        values.put(Telephony.Carriers.MMSPROXY, "");
+        values.put(Telephony.Carriers.MMSPORT, "");
+        values.put(Telephony.Carriers.USER, "");
+        values.put(Telephony.Carriers.SERVER, "");
+        values.put(Telephony.Carriers.PASSWORD, "");
+        values.put(Telephony.Carriers.MMSC, "");
+        values.put(Telephony.Carriers.TYPE, type);
+        values.put(Telephony.Carriers.MCC, mcc);
+        values.put(Telephony.Carriers.MNC, mnc);
+        values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
+
+        int ret = mService.getContentResolver().update(uri, values, null, null);
+        Log.d("after update " + ret);
+        cursor.close();
+
+        // Make this APN as the preferred
+        String where = "name=\"" + name + "\"";
+
+        Cursor c = mService.getContentResolver().query(
+                Telephony.Carriers.CONTENT_URI,
+                new String[] {
+                        "_id", "name", "apn", "type"
+                }, where, null,
+                Telephony.Carriers.DEFAULT_SORT_ORDER);
+        if (c != null) {
+            c.moveToFirst();
+            String key = c.getString(0);
+            final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";
+            ContentResolver resolver = mService.getContentResolver();
+            ContentValues prefAPN = new ContentValues();
+            prefAPN.put("apn_id", key);
+            resolver.update(Uri.parse(PREFERRED_APN_URI), prefAPN, null, null);
+        }
+        c.close();
+    }
+
+    @Rpc(description = "Returns the number of APNs defined")
+    public int getNumberOfAPNs() {
+        int noOfAPN = 0;
+        String where = "numeric=\""
+                + android.os.SystemProperties.get(
+                        TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "")
+                + "\"";
+
+        Cursor cursor = mService.getContentResolver().query(
+                Telephony.Carriers.CONTENT_URI,
+                new String[] {
+                        "_id", "name", "apn", "type"
+                }, where, null,
+                Telephony.Carriers.DEFAULT_SORT_ORDER);
+
+        if (cursor != null) {
+            noOfAPN = cursor.getCount();
+        }
+        cursor.close();
+        return noOfAPN;
+    }
+
+    @Rpc(description = "Returns the currently selected APN name")
+    public String getSelectedAPN() {
+        String key = null;
+        int ID_INDEX = 0;
+        final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";
+
+        Cursor cursor = mService.getContentResolver().query(
+                Uri.parse(PREFERRED_APN_URI), new String[] {
+                    "name"
+                }, null,
+                null, Telephony.Carriers.DEFAULT_SORT_ORDER);
+        if (cursor.getCount() > 0) {
+            cursor.moveToFirst();
+            key = cursor.getString(ID_INDEX);
+        }
+        cursor.close();
+        return key;
+    }
+}
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java
index 8bfd3ed..936044f 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothLeAdvertiseFacade.java
@@ -627,5 +627,4 @@
             mAdvertiseDataList.clear();
         }
     }
-
 }