Add mobile data on/off switch.

bug:2251458
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index badb767..c76aca1 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -332,10 +332,10 @@
 
     /**
      * Sets the value of the setting for background data usage.
-     * 
+     *
      * @param allowBackgroundData Whether an application should use data while
      *            it is in the background.
-     *            
+     *
      * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING
      * @see #getBackgroundDataSetting()
      * @hide
@@ -346,7 +346,35 @@
         } catch (RemoteException e) {
         }
     }
-    
+
+    /**
+     * Gets the value of the setting for enabling Mobile data.
+     *
+     * @return Whether mobile data is enabled.
+     * @hide
+     */
+    public boolean getMobileDataEnabled() {
+        try {
+            return mService.getMobileDataEnabled();
+        } catch (RemoteException e) {
+            return true;
+        }
+    }
+
+    /**
+     * Sets the persisted value for enabling/disabling Mobile data.
+     *
+     * @param allowMobileData Whether the mobile data connection should be
+     *            used or not.
+     * @hide
+     */
+    public void setMobileDataEnabled(boolean enabled) {
+        try {
+            mService.setMobileDataEnabled(enabled);
+        } catch (RemoteException e) {
+        }
+    }
+
     /**
      * Don't allow use of default constructor.
      */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 508e9c3a..2514693 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -51,6 +51,10 @@
 
     void setBackgroundDataSetting(boolean allowBackgroundData);
 
+    boolean getMobileDataEnabled();
+
+    void setMobileDataEnabled(boolean enabled);
+
     boolean tether(String iface);
 
     boolean untether(String iface);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a020da4..b75a8cc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2466,6 +2466,13 @@
         public static final String BACKGROUND_DATA = "background_data";
 
         /**
+         * Whether mobile data connections are allowed by the user.  See
+         * ConnectivityManager for more info.
+         * @hide
+         */
+        public static final String MOBILE_DATA = "mobile_data";
+
+        /**
          * The CDMA roaming mode 0 = Home Networks, CDMA default
          *                       1 = Roaming on Affiliated networks
          *                       2 = Roaming on any networks
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 108246d..df685ab 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -289,6 +289,7 @@
          * the number of different network types is not going
          * to change very often.
          */
+        boolean noMobileData = !getMobileDataEnabled();
         for (int netType : mPriorityList) {
             switch (mNetAttributes[netType].mRadio) {
             case ConnectivityManager.TYPE_WIFI:
@@ -306,6 +307,10 @@
                 mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
                     netType, mNetAttributes[netType].mName);
                 mNetTrackers[netType].startMonitoring();
+                if (noMobileData) {
+                    if (DBG) Log.d(TAG, "tearing down Mobile networks due to setting");
+                    mNetTrackers[netType].teardown();
+                }
                 break;
             default:
                 Log.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
@@ -530,6 +535,10 @@
         // TODO - move this into the MobileDataStateTracker
         int usedNetworkType = networkType;
         if(networkType == ConnectivityManager.TYPE_MOBILE) {
+            if (!getMobileDataEnabled()) {
+                if (DBG) Log.d(TAG, "requested special network with data disabled - rejected");
+                return Phone.APN_TYPE_NOT_AVAILABLE;
+            }
             if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
                 usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
             } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
@@ -767,6 +776,46 @@
         mContext.sendBroadcast(broadcast);
     }
 
+    /**
+     * @see ConnectivityManager#getMobileDataEnabled()
+     */
+    public boolean getMobileDataEnabled() {
+        enforceAccessPermission();
+        boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.MOBILE_DATA, 1) == 1;
+        if (DBG) Log.d(TAG, "getMobileDataEnabled returning " + retVal);
+        return retVal;
+    }
+
+    /**
+     * @see ConnectivityManager#setMobileDataEnabled(boolean)
+     */
+    public synchronized void setMobileDataEnabled(boolean enabled) {
+        enforceChangePermission();
+        if (DBG) Log.d(TAG, "setMobileDataEnabled(" + enabled + ")");
+
+        if (getMobileDataEnabled() == enabled) return;
+
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
+
+        if (enabled) {
+            if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
+                if (DBG) Log.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
+                mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
+            }
+        } else {
+            for (NetworkStateTracker nt : mNetTrackers) {
+                if (nt == null) continue;
+                int netType = nt.getNetworkInfo().getType();
+                if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
+                    if (DBG) Log.d(TAG, "tearing down " + nt);
+                    nt.teardown();
+                }
+            }
+        }
+    }
+
     private int getNumConnectedNetworks() {
         int numConnectedNets = 0;
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index fbb3c4c..d5f18e0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -23,6 +23,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
@@ -188,8 +190,16 @@
         // and 2) whether the RIL will setup the baseband to auto-PS attach.
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
 
+        boolean dataEnabledSetting = true;
+        try {
+            dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager.
+                    getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled();
+        } catch (Exception e) {
+            // nothing to do - use the old behavior and leave data on
+        }
         dataEnabled[APN_DEFAULT_ID] =
-                !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false);
+                !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false) &&
+                dataEnabledSetting;
         if (dataEnabled[APN_DEFAULT_ID]) {
             enabledCount++;
         }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 1fd6be8..30beaaa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -27,6 +27,8 @@
 import android.content.SharedPreferences;
 import android.database.ContentObserver;
 import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
@@ -243,7 +245,15 @@
         // This preference tells us 1) initial condition for "dataEnabled",
         // and 2) whether the RIL will setup the baseband to auto-PS attach.
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
-        dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
+        boolean dataEnabledSetting = true;
+        try {
+            dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager.
+                getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled();
+        } catch (Exception e) {
+            // nothing to do - use the old behavior and leave data on
+        }
+        dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false) &&
+                dataEnabledSetting;
         if (dataEnabled[APN_DEFAULT_ID]) {
             enabledCount++;
         }