Disable VT when users turn off data or hit data limit

Disable VT when users turn off data or hit data limit. If
there are ongoing VT calls, we'll need to downgrade them
to VoLTE calls.

bug: 27316521
Change-Id: I7988d0475583e7fec50888eaee1e5a0d4d5b8cc6
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index aafcfc7..bbecd9c 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -185,7 +185,7 @@
     // Carrier's CDMA prefer mode setting
     protected static final int EVENT_SET_ROAMING_PREFERENCE_DONE    = 44;
 
-    protected static final int EVENT_LAST                           = EVENT_CARRIER_CONFIG_CHANGED;
+    protected static final int EVENT_LAST                       = EVENT_SET_ROAMING_PREFERENCE_DONE;
 
     // For shared prefs.
     private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
@@ -2636,7 +2636,7 @@
      */
     public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
         if(mDcTracker != null) {
-            mDcTracker.carrierActionSetMeteredApnsEnabled(enabled);
+            mDcTracker.setApnsEnabledByCarrier(enabled);
         }
     }
 
@@ -3242,6 +3242,14 @@
         mDcTracker.unregisterForAllDataDisconnected(h);
     }
 
+    public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
+        mDcTracker.registerForDataEnabledChanged(h, what, obj);
+    }
+
+    public void unregisterForDataEnabledChanged(Handler h) {
+        mDcTracker.unregisterForDataEnabledChanged(h);
+    }
+
     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
         return null;
     }
@@ -3305,6 +3313,14 @@
         return mImsPhone.getVtDataUsage();
     }
 
+    /**
+     * Policy control of data connection. Usually used when we hit data limit.
+     * @param enabled True if enabling the data, otherwise disabling.
+     */
+    public void setPolicyDataEnabled(boolean enabled) {
+        mDcTracker.setPolicyDataEnabled(enabled);
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Phone: subId=" + getSubId());
         pw.println(" mPhoneId=" + mPhoneId);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index b19b602..c1319a4 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -873,7 +873,7 @@
             return;
         }
 
-        // Is user data disabled?
+        // Is data disabled?
         mRestrictedNetworkOverride = (mDct.isDataEnabled(true) == false);
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
new file mode 100644
index 0000000..9fdb5e1
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.android.internal.telephony.dataconnection;
+
+
+import android.os.Handler;
+import android.os.RegistrantList;
+import android.util.Pair;
+
+/**
+ * The class to hold different data enabled/disabled settings. Also it allows clients to register
+ * for overall data enabled setting changed event.
+ * @hide
+ */
+public class DataEnabledSettings {
+
+    private static final int REASON_REGISTERED = 0;
+
+    private static final int REASON_INTERNAL_DATA_ENABLED = 1;
+
+    private static final int REASON_USER_DATA_ENABLED = 2;
+
+    private static final int REASON_POLICY_DATA_ENABLED = 3;
+
+    private static final int REASON_DATA_ENABLED_BY_CARRIER = 4;
+
+    /**
+     * responds to the setInternalDataEnabled call - used internally to turn off data.
+     * For example during emergency calls
+     */
+    private boolean mInternalDataEnabled = true;
+
+    /**
+     * responds to public (user) API to enable/disable data use independent of
+     * mInternalDataEnabled and requests for APN access persisted
+     */
+    private boolean mUserDataEnabled = true;
+
+    /**
+     * Flag indicating data allowed by network policy manager or not.
+     */
+    private boolean mPolicyDataEnabled = true;
+
+    /**
+     * Indicate if metered APNs are enabled by the carrier. set false to block all the metered APNs
+     * from continuously sending requests, which causes undesired network load.
+     */
+    private boolean mCarrierDataEnabled = true;
+
+    private final RegistrantList mDataEnabledChangedRegistrants = new RegistrantList();
+
+    public synchronized void setInternalDataEnabled(boolean enabled) {
+        boolean prevDataEnabled = isDataEnabled(true);
+        mInternalDataEnabled = enabled;
+        if (prevDataEnabled != isDataEnabled(true)) {
+            notifyDataEnabledChanged(!prevDataEnabled, REASON_INTERNAL_DATA_ENABLED);
+        }
+    }
+    public synchronized boolean isInternalDataEnabled() {
+        return mInternalDataEnabled;
+    }
+
+    public synchronized void setUserDataEnabled(boolean enabled) {
+        boolean prevDataEnabled = isDataEnabled(true);
+        mUserDataEnabled = enabled;
+        if (prevDataEnabled != isDataEnabled(true)) {
+            notifyDataEnabledChanged(!prevDataEnabled, REASON_USER_DATA_ENABLED);
+        }
+    }
+    public synchronized boolean isUserDataEnabled() {
+        return mUserDataEnabled;
+    }
+
+    public synchronized void setPolicyDataEnabled(boolean enabled) {
+        boolean prevDataEnabled = isDataEnabled(true);
+        mPolicyDataEnabled = enabled;
+        if (prevDataEnabled != isDataEnabled(true)) {
+            notifyDataEnabledChanged(!prevDataEnabled, REASON_POLICY_DATA_ENABLED);
+        }
+    }
+    public synchronized boolean isPolicyDataEnabled() {
+        return mPolicyDataEnabled;
+    }
+
+    public synchronized void setCarrierDataEnabled(boolean enabled) {
+        boolean prevDataEnabled = isDataEnabled(true);
+        mCarrierDataEnabled = enabled;
+        if (prevDataEnabled != isDataEnabled(true)) {
+            notifyDataEnabledChanged(!prevDataEnabled, REASON_DATA_ENABLED_BY_CARRIER);
+        }
+    }
+    public synchronized boolean isCarrierDataEnabled() {
+        return mCarrierDataEnabled;
+    }
+
+    public synchronized boolean isDataEnabled(boolean checkUserDataEnabled) {
+        return (mInternalDataEnabled
+                && (!checkUserDataEnabled || mUserDataEnabled)
+                && (!checkUserDataEnabled || mPolicyDataEnabled)
+                && (!checkUserDataEnabled || mCarrierDataEnabled));
+    }
+
+    private void notifyDataEnabledChanged(boolean enabled, int reason) {
+        mDataEnabledChangedRegistrants.notifyResult(new Pair<>(enabled, reason));
+    }
+
+    public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
+        mDataEnabledChangedRegistrants.addUnique(h, what, obj);
+        notifyDataEnabledChanged(isDataEnabled(true), REASON_REGISTERED);
+    }
+
+    public void unregisterForDataEnabledChanged(Handler h) {
+        mDataEnabledChangedRegistrants.remove(h);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 9821733..25b82ef 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -118,23 +118,12 @@
 
     private final AlarmManager mAlarmManager;
 
-    private Object mDataEnabledLock = new Object();
-
-    // responds to the setInternalDataEnabled call - used internally to turn off data
-    // for example during emergency calls
-    private boolean mInternalDataEnabled = true;
-
-    // responds to public (user) API to enable/disable data use
-    // independent of mInternalDataEnabled and requests for APN access
-    // persisted
-    private boolean mUserDataEnabled = true;
-
-    // TODO: move away from static state once 5587429 is fixed.
-    private static boolean sPolicyDataEnabled = true;
-
     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
     private String mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
 
+    // All data enabling/disabling related settings
+    private final DataEnabledSettings mDataEnabledSettings = new DataEnabledSettings();
+
     /**
      * After detecting a potential connection problem, this is the max number
      * of subsequent polls before attempting recovery.
@@ -690,7 +679,7 @@
         filter.addAction(INTENT_PROVISIONING_APN_ALARM);
 
         // TODO - redundent with update call below?
-        mUserDataEnabled = getDataEnabled();
+        mDataEnabledSettings.setUserDataEnabled(getDataEnabled());
 
         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
 
@@ -872,10 +861,11 @@
     }
 
     private void onSetUserDataEnabled(boolean enabled) {
-        synchronized (mDataEnabledLock) {
-            if (mUserDataEnabled != enabled) {
-                mUserDataEnabled = enabled;
+        synchronized (mDataEnabledSettings) {
+            if (mDataEnabledSettings.isUserDataEnabled() != enabled) {
+                mDataEnabledSettings.setUserDataEnabled(enabled);
 
+                //TODO: We should move the followings into DataEnabledSettings class.
                 // For single SIM phones, this is a per phone property.
                 if (TelephonyManager.getDefault().getSimCount() == 1) {
                     Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA, enabled ? 1 : 0);
@@ -893,6 +883,8 @@
                     }
                 }
 
+                // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
+                // handle the rest from there.
                 if (enabled) {
                     teardownRestrictedMeteredConnections();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
@@ -912,7 +904,7 @@
      * to it in an unrestricted way.
      */
     private void teardownRestrictedMeteredConnections() {
-        if (isDataEnabled(true)) {
+        if (mDataEnabledSettings.isDataEnabled(true)) {
             for (ApnContext apnContext : mApnContexts.values()) {
                 if (apnContext.isConnectedOrConnecting() &&
                         apnContext.getApnSetting().isMetered(mPhone.getContext(),
@@ -927,11 +919,11 @@
 
     private void onDeviceProvisionedChange() {
         if (getDataEnabled()) {
-            mUserDataEnabled = true;
+            mDataEnabledSettings.setUserDataEnabled(true);
             teardownRestrictedMeteredConnections();
             onTrySetupData(Phone.REASON_DATA_ENABLED);
         } else {
-            mUserDataEnabled = false;
+            mDataEnabledSettings.setUserDataEnabled(false);
             onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
         }
     }
@@ -1268,7 +1260,7 @@
      * {@code true} otherwise.
      */
     public boolean getAnyDataEnabled() {
-        if (!isDataEnabled(true)) return false;
+        if (!mDataEnabledSettings.isDataEnabled(true)) return false;
         DataAllowFailReason failureReason = new DataAllowFailReason();
         if (!isDataAllowed(failureReason)) {
             if (DBG) log(failureReason.getDataAllowFailReason());
@@ -1284,33 +1276,9 @@
         return false;
     }
 
-    public boolean getAnyDataEnabled(boolean checkUserDataEnabled) {
-        if (!isDataEnabled(checkUserDataEnabled)) return false;
-
-        DataAllowFailReason failureReason = new DataAllowFailReason();
-        if (!isDataAllowed(failureReason)) {
-            if (DBG) log(failureReason.getDataAllowFailReason());
-            return false;
-        }
-        for (ApnContext apnContext : mApnContexts.values()) {
-            // Make sure we dont have a context that going down
-            // and is explicitly disabled.
-            if (isDataAllowedForApn(apnContext)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     @VisibleForTesting
     public boolean isDataEnabled(boolean checkUserDataEnabled) {
-        synchronized (mDataEnabledLock) {
-            if (!(mInternalDataEnabled && (!checkUserDataEnabled || mUserDataEnabled)
-                    && (!checkUserDataEnabled || sPolicyDataEnabled)
-                    && (!checkUserDataEnabled || !mMeteredApnDisabled)))
-                return false;
-        }
-        return true;
+        return mDataEnabledSettings.isDataEnabled(checkUserDataEnabled);
     }
 
     private boolean isDataAllowedForApn(ApnContext apnContext) {
@@ -1364,9 +1332,7 @@
 
     private boolean isDataAllowed(DataAllowFailReason failureReason) {
         final boolean internalDataEnabled;
-        synchronized (mDataEnabledLock) {
-            internalDataEnabled = mInternalDataEnabled;
-        }
+        internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
 
         boolean attachedState = mAttached.get();
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
@@ -1513,10 +1479,7 @@
     }
 
     boolean isEmergency() {
-        final boolean result;
-        synchronized (mDataEnabledLock) {
-            result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
-        }
+        final boolean result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
         log("isEmergency: result=" + result);
         return result;
     }
@@ -1567,7 +1530,7 @@
 
         if (apnContext.isConnectable() && (isEmergencyApn ||
                 (isDataAllowed && isDataAllowedForApn(apnContext) &&
-                isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
+                        mDataEnabledSettings.isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
             if (apnContext.getState() == DctConstants.State.FAILED) {
                 String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
                 if (DBG) log(str);
@@ -1625,11 +1588,13 @@
                 str.append("isDataAllowedForApn = false. RAT = " +
                         mPhone.getServiceState().getRilDataRadioTechnology());
             }
-            if (!isDataEnabled(checkUserDataEnabled)) {
+            if (!mDataEnabledSettings.isDataEnabled(checkUserDataEnabled)) {
                 str.append("isDataEnabled(" + checkUserDataEnabled + ") = false. " +
-                        "mInternalDataEnabled = " + mInternalDataEnabled + " , mUserDataEnabled = "
-                        + mUserDataEnabled + ", sPolicyDataEnabled = " + sPolicyDataEnabled +
-                        ", mMeteredApnDisabled = " + mMeteredApnDisabled);
+                        "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled() +
+                        ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled() +
+                        ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled() +
+                        ", isCarrierDataEnabled = " +
+                        mDataEnabledSettings.isCarrierDataEnabled());
             }
             if (isEmergency()) {
                 str.append("emergency = true");
@@ -2379,24 +2344,34 @@
         setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
     }
 
+    public void setApnsEnabledByCarrier(boolean enabled) {
+        Message msg = obtainMessage(DctConstants.EVENT_SET_CARRIER_DATA_ENABLED);
+        msg.arg1 = (enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
+        sendMessage(msg);
+    }
+
     /**
      * Action set from carrier signalling broadcast receivers to enable/disable metered apns.
      */
-    public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
-        if (enabled == mMeteredApnDisabled) {
-            if (DBG) {
-                log("carrier Action: set metered apns enabled: " + enabled);
-            }
-            // Disable/enable all metered apns
-            mMeteredApnDisabled = !enabled;
-            if (!enabled) {
-                // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
-                mPhone.notifyOtaspChanged(ServiceStateTracker.OTASP_SIM_UNPROVISIONED);
-                // Tear down all metered apns
-                cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
-            } else {
-                teardownRestrictedMeteredConnections();
-                setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
+    private void onSetCarrierDataEnabled(boolean enabled) {
+        synchronized (mDataEnabledSettings) {
+            if (enabled != mDataEnabledSettings.isCarrierDataEnabled()) {
+                if (DBG) {
+                    log("carrier Action: set metered apns enabled: " + enabled);
+                }
+
+                // Disable/enable all metered apns
+                mDataEnabledSettings.setCarrierDataEnabled(enabled);
+
+                if (!enabled) {
+                    // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
+                    mPhone.notifyOtaspChanged(ServiceStateTracker.OTASP_SIM_UNPROVISIONED);
+                    // Tear down all metered apns
+                    cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
+                } else {
+                    teardownRestrictedMeteredConnections();
+                    setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
+                }
             }
         }
     }
@@ -2438,11 +2413,20 @@
         }
     }
 
+    public void setPolicyDataEnabled(boolean enabled) {
+        if (DBG) log("setPolicyDataEnabled: " + enabled);
+        Message msg = obtainMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE);
+        msg.arg1 = (enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
+        sendMessage(msg);
+    }
+
     private void onSetPolicyDataEnabled(boolean enabled) {
-        synchronized (mDataEnabledLock) {
+        synchronized (mDataEnabledSettings) {
             final boolean prevEnabled = getAnyDataEnabled();
-            if (sPolicyDataEnabled != enabled) {
-                sPolicyDataEnabled = enabled;
+            if (mDataEnabledSettings.isPolicyDataEnabled() != enabled) {
+                mDataEnabledSettings.setPolicyDataEnabled(enabled);
+                // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
+                // handle the rest from there.
                 if (prevEnabled != getAnyDataEnabled()) {
                     if (!prevEnabled) {
                         teardownRestrictedMeteredConnections();
@@ -2455,7 +2439,6 @@
         }
     }
 
-
     private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
         boolean cleanup = false;
         boolean trySetup = false;
@@ -2636,6 +2619,7 @@
     /**
      * Return current {@link android.provider.Settings.Global#MOBILE_DATA} value.
      */
+    //TODO: Merge this into DataSettings. And probably should rename to getUserDataEnabled().
     public boolean getDataEnabled() {
         final int device_provisioned =
                 Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0);
@@ -2736,7 +2720,7 @@
     private void onRoamingOff() {
         if (DBG) log("onRoamingOff");
 
-        if (!mUserDataEnabled) return;
+        if (!mDataEnabledSettings.isUserDataEnabled()) return;
 
         if (getDataOnRoamingEnabled() == false) {
             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF);
@@ -2749,7 +2733,7 @@
     private void onRoamingOn() {
         if (DBG) log("onRoamingOn");
 
-        if (!mUserDataEnabled) {
+        if (!mDataEnabledSettings.isUserDataEnabled()) {
             if (DBG) log("data not enabled by user");
             return;
         }
@@ -3029,7 +3013,7 @@
         /* If flag is set to false after SETUP_DATA_CALL is invoked, we need
          * to clean data connections.
          */
-        if (!mInternalDataEnabled) {
+        if (!mDataEnabledSettings.isInternalDataEnabled()) {
             cleanUpAllConnections(Phone.REASON_DATA_DISABLED);
         }
 
@@ -3992,6 +3976,9 @@
                 handlePcoData((AsyncResult)msg.obj);
                 break;
             }
+            case DctConstants.EVENT_SET_CARRIER_DATA_ENABLED:
+                onSetCarrierDataEnabled(msg.arg1 == DctConstants.ENABLED);
+                break;
             default:
                 Rlog.e("DcTracker", "Unhandled event=" + msg);
                 break;
@@ -4057,7 +4044,7 @@
                     // reset carrier actions on sim loaded
                     final ServiceStateTracker sst = mPhone.getServiceStateTracker();
                     sst.setRadioPowerFromCarrier(true);
-                    mMeteredApnDisabled = false;
+                    mDataEnabledSettings.setCarrierDataEnabled(true);
                     mPhone.getCarrierSignalAgent().reset();
                 }
             } else {
@@ -4071,7 +4058,7 @@
         log("update(): Active DDS, register for all events now!");
         onUpdateIcc();
 
-        mUserDataEnabled = getDataEnabled();
+        mDataEnabledSettings.setUserDataEnabled(getDataEnabled());
         mAutoAttachOnCreation.set(false);
 
         ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider();
@@ -4124,13 +4111,20 @@
         mAllDataDisconnectedRegistrants.remove(h);
     }
 
+    public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
+        mDataEnabledSettings.registerForDataEnabledChanged(h, what, obj);
+    }
+
+    public void unregisterForDataEnabledChanged(Handler h) {
+        mDataEnabledSettings.unregisterForDataEnabledChanged(h);
+    }
 
     private void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) {
-        if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled);
-        boolean sendOnComplete = true;
+        synchronized (mDataEnabledSettings) {
+            if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled);
+            boolean sendOnComplete = true;
 
-        synchronized (mDataEnabledLock) {
-            mInternalDataEnabled = enabled;
+            mDataEnabledSettings.setInternalDataEnabled(enabled);
             if (enabled) {
                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
                 onTrySetupData(Phone.REASON_DATA_ENABLED);
@@ -4139,24 +4133,15 @@
                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
                 cleanUpAllConnections(Phone.REASON_DATA_DISABLED, onCompleteMsg);
             }
-        }
 
-        if (sendOnComplete) {
-            if (onCompleteMsg != null) {
-                onCompleteMsg.sendToTarget();
+            if (sendOnComplete) {
+                if (onCompleteMsg != null) {
+                    onCompleteMsg.sendToTarget();
+                }
             }
         }
     }
 
-    public boolean setInternalDataEnabledFlag(boolean enable) {
-        if (DBG) log("setInternalDataEnabledFlag(" + enable + ")");
-
-        if (mInternalDataEnabled != enable) {
-            mInternalDataEnabled = enable;
-        }
-        return true;
-    }
-
     public boolean setInternalDataEnabled(boolean enable) {
         return setInternalDataEnabled(enable, null);
     }
@@ -4170,13 +4155,6 @@
         return true;
     }
 
-    public void setDataAllowed(boolean enable, Message response) {
-         if (DBG) log("setDataAllowed: enable=" + enable);
-         isCleanupRequired.set(!enable);
-         mPhone.mCi.setDataAllowed(enable, response);
-         mInternalDataEnabled = enable;
-    }
-
     private void log(String s) {
         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
     }
@@ -4188,9 +4166,9 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("DcTracker:");
         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
-        pw.println(" mInternalDataEnabled=" + mInternalDataEnabled);
-        pw.println(" mUserDataEnabled=" + mUserDataEnabled);
-        pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled);
+        pw.println(" isInternalDataEnabled=" + mDataEnabledSettings.isInternalDataEnabled());
+        pw.println(" isUserDataEnabled=" + mDataEnabledSettings.isUserDataEnabled());
+        pw.println(" isPolicyDataEnabled=" + mDataEnabledSettings.isPolicyDataEnabled());
         pw.flush();
         pw.println(" mRequestedApnType=" + mRequestedApnType);
         pw.println(" mPhone=" + mPhone.getPhoneName());
@@ -4202,7 +4180,7 @@
         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
-        pw.println(" mDataStallDetectionEanbled=" + mDataStallDetectionEnabled);
+        pw.println(" mDataStallDetectionEnabled=" + mDataStallDetectionEnabled);
         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
         pw.println(" mResolver=" + mResolver);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index d9ba2bd..897b374 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -194,6 +194,7 @@
     private static final int EVENT_DIAL_PENDINGMO = 20;
     private static final int EVENT_EXIT_ECBM_BEFORE_PENDINGMO = 21;
     private static final int EVENT_VT_DATA_USAGE_UPDATE = 22;
+    private static final int EVENT_DATA_ENABLED_CHANGED = 23;
 
     private static final int TIMEOUT_HANGUP_PENDINGMO = 500;
 
@@ -293,6 +294,9 @@
         mPhone.getContext().registerReceiver(mReceiver, intentfilter);
         cacheCarrierConfiguration(mPhone.getSubId());
 
+        mPhone.getDefaultPhone().registerForDataEnabledChanged(
+                this, EVENT_DATA_ENABLED_CHANGED, null);
+
         Thread t = new Thread() {
             public void run() {
                 getImsService();
@@ -351,6 +355,7 @@
 
         clearDisconnected();
         mPhone.getContext().unregisterReceiver(mReceiver);
+        mPhone.unregisterForDataEnabledChanged(this);
     }
 
     @Override
@@ -2141,6 +2146,13 @@
                 mTotalVtDataUsage += (usage - oldUsage);
                 mVtDataUsageMap.put(call.uniqueId, usage);
                 break;
+            case EVENT_DATA_ENABLED_CHANGED:
+                ar = (AsyncResult) msg.obj;
+                if (ar.result instanceof Pair) {
+                    Pair<Boolean, Integer> p = (Pair<Boolean, Integer>) ar.result;
+                    onDataEnabledChanged(p.first, p.second);
+                }
+                break;
         }
     }
 
@@ -2459,5 +2471,45 @@
         }
     }
 
+    /** Modify video call to a new video state.
+     *
+     * @param imsCall IMS call to be modified
+     * @param newVideoState New video state. (Refer to VideoProfile)
+     */
+    private void modifyVideoCall(ImsCall imsCall, int newVideoState) {
+        ImsPhoneConnection conn = findConnection(imsCall);
+        if (conn != null) {
+            int oldVideoState = conn.getVideoState();
+            if (conn.getVideoProvider() != null) {
+                conn.getVideoProvider().onSendSessionModifyRequest(
+                        new VideoProfile(oldVideoState), new VideoProfile(newVideoState));
+            }
+        }
+    }
 
+    /**
+     * Handler of data enabled changed event
+     * @param enabled True if data is enabled, otherwise disabled.
+     * @param reason Reason for data enabled/disabled
+     */
+    private void onDataEnabledChanged(boolean enabled, int reason) {
+
+        log("onDataEnabledChanged: enabled=" + enabled + ", reason=" + reason);
+        ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()).setDataEnabled(enabled);
+
+        if (enabled == false) {
+            // If data are disabled while there are ongoing VT calls, we need to downgrade
+            // the VT calls (except on VT over Wifi)
+            for (ImsPhoneConnection conn : mConnections) {
+                ImsCall imsCall = conn.getImsCall();
+                if (imsCall != null && imsCall.isVideoCall() && !imsCall.isWifiCall()) {
+                    modifyVideoCall(imsCall, VideoProfile.STATE_AUDIO_ONLY);
+                }
+            }
+        }
+
+        // This will call into updateVideoCallFeatureValue and eventually all clients will be
+        // asynchronously notified that the availability of VT over LTE has changed.
+        ImsManager.updateImsServiceConfig(mPhone.getContext(), mPhone.getPhoneId(), true);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 976f418..101640e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -348,6 +348,7 @@
         doReturn(mIccCardProxy).when(mPhone).getIccCard();
         doReturn(mServiceState).when(mPhone).getServiceState();
         doReturn(mServiceState).when(mImsPhone).getServiceState();
+        doReturn(mPhone).when(mImsPhone).getDefaultPhone();
         doReturn(true).when(mPhone).isPhoneTypeGsm();
         doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mPhone).getPhoneType();
         doReturn(mCT).when(mPhone).getCallTracker();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index 99b8131..2ce6324 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -794,7 +794,7 @@
                 eq(""), eq(""), eq(0), eq("IP"), any(Message.class));
         assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
 
-        mDct.carrierActionSetMeteredApnsEnabled(false);
+        mDct.setApnsEnabledByCarrier(false);
         waitForMs(100);
 
         // Validate all metered data connections have been torn down
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
index c4bc0af..7cc2870 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
@@ -94,10 +94,6 @@
         throw new RuntimeException("Not Implemented");
     }
     @Override
-    public boolean getAnyDataEnabled(boolean checkUserDataEnabled) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
     public boolean hasMatchedTetherApnSetting() {
         throw new RuntimeException("Not Implemented");
     }
@@ -146,18 +142,10 @@
         throw new RuntimeException("Not Implemented");
     }
     @Override
-    public boolean setInternalDataEnabledFlag(boolean enable) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
     public boolean setInternalDataEnabled(boolean enable) {
         throw new RuntimeException("Not Implemented");
     }
     @Override
-    public void setDataAllowed(boolean enable, Message response) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
     public String[] getPcscfAddress(String apnType) {
         throw new RuntimeException("Not Implemented");
     }