Merge "Fixed that RAT_UNKNOWN incorretly reported in metrics data." into nyc-mr1-dev
diff --git a/src/java/android/telephony/SmsManager.java b/src/java/android/telephony/SmsManager.java
index 4df3b40..8063364 100644
--- a/src/java/android/telephony/SmsManager.java
+++ b/src/java/android/telephony/SmsManager.java
@@ -245,6 +245,14 @@
      */
     public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER =
             CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL;
+    /**
+     * If true, add "Connection: close" header to MMS HTTP requests so the connection
+     * is immediately closed (disabling keep-alive). (Boolean type)
+     * @hide
+     */
+    public static final String MMS_CONFIG_CLOSE_CONNECTION =
+            CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL;
+
     /*
      * Forwarded constants from SimDialogActivity.
      */
@@ -1618,6 +1626,8 @@
                 config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED));
         filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED,
                 config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED));
+        filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION,
+                config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION));
         filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE));
         filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH));
         filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT));
diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java
index 3ba791d..d4e53d7 100644
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -98,6 +98,7 @@
         public void onConferenceMergedFailed();
         public void onExtrasChanged(Bundle extras);
         public void onExitedEcmMode();
+        public void onCallPullFailed(Connection externalConnection);
     }
 
     /**
@@ -127,6 +128,8 @@
         public void onExtrasChanged(Bundle extras) {}
         @Override
         public void onExitedEcmMode() {}
+        @Override
+        public void onCallPullFailed(Connection externalConnection) {}
     }
 
     public static final int AUDIO_QUALITY_STANDARD = 1;
@@ -194,6 +197,13 @@
      */
     private boolean mIsPulledCall = false;
 
+    /**
+     * Where {@link #mIsPulledCall} is {@code true}, contains the dialog Id of the external call
+     * which is being pulled (e.g.
+     * {@link com.android.internal.telephony.imsphone.ImsExternalConnection#getCallId()}).
+     */
+    private int mPulledDialogId;
+
     protected Connection(int phoneType) {
         mPhoneType = phoneType;
     }
@@ -828,6 +838,21 @@
     }
 
     /**
+     * For an external call which is being pulled (e.g. {@link #isPulledCall()} is {@code true}),
+     * sets the dialog Id for the external call.  Used to handle failures to pull a call so that the
+     * pulled call can be reconciled with its original external connection.
+     *
+     * @param pulledDialogId The dialog id associated with a pulled call.
+     */
+    public void setPulledDialogId(int pulledDialogId) {
+        mPulledDialogId = pulledDialogId;
+    }
+
+    public int getPulledDialogId() {
+        return mPulledDialogId;
+    }
+
+    /**
      * Sets the call substate for the current connection and reports the changes to all listeners.
      * Valid call substates are defined in {@link android.telecom.Connection}.
      *
@@ -900,6 +925,20 @@
     }
 
     /**
+     * Notifies the connection that a call to {@link #pullExternalCall()} has failed to pull the
+     * call to the local device.
+     *
+     * @param externalConnection The original
+     *      {@link com.android.internal.telephony.imsphone.ImsExternalConnection} from which the
+     *      pull was initiated.
+     */
+    public void onCallPullFailed(Connection externalConnection) {
+        for (Listener l : mListeners) {
+            l.onCallPullFailed(externalConnection);
+        }
+    }
+
+    /**
      * Notifies this Connection of a request to disconnect a participant of the conference managed
      * by the connection.
      *
@@ -931,6 +970,8 @@
         StringBuilder str = new StringBuilder(128);
 
         str.append(" callId: " + getTelecomCallId());
+        str.append(" isExternal: " + (((mConnectionCapabilities & Capability.IS_EXTERNAL_CONNECTION)
+                == Capability.IS_EXTERNAL_CONNECTION) ? "Y" : "N"));
         if (Rlog.isLoggable(LOG_TAG, Log.DEBUG)) {
             str.append("addr: " + getAddress())
                     .append(" pres.: " + getNumberPresentation())
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 173f25e..1392302 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -185,6 +185,8 @@
 
     private int mRilVersion;
     private boolean mBroadcastEmergencyCallStateChanges = false;
+    // flag to indicate if emergency call end broadcast should be sent
+    boolean mSendEmergencyCallEnd = true;
 
     // Constructors
 
@@ -637,11 +639,24 @@
     @Override
     public void sendEmergencyCallStateChange(boolean callActive) {
         if (mBroadcastEmergencyCallStateChanges) {
-            Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
-            intent.putExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, callActive);
-            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
-            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
-            if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange");
+            if (callActive &&
+                    getServiceState().getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
+                // if emergency call is started while on iwlan, do not send the start or end
+                // broadcast
+                mSendEmergencyCallEnd = false;
+                if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: not sending call start " +
+                        "intent as voice tech is IWLAN");
+            } else if (callActive || mSendEmergencyCallEnd) {
+                Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
+                intent.putExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, callActive);
+                SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
+                ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+                if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange");
+            } else {
+                if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: not sending call end " +
+                        "intent as start was not sent");
+                mSendEmergencyCallEnd = true;
+            }
         }
     }
 
@@ -1356,6 +1371,12 @@
         if (isPhoneTypeGsm()) {
             return mImei;
         } else {
+            CarrierConfigManager configManager = (CarrierConfigManager)
+                    mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            boolean force_imei = configManager.getConfigForSubId(getSubId())
+                    .getBoolean(CarrierConfigManager.KEY_FORCE_IMEI_BOOL);
+            if (force_imei) return mImei;
+
             String id = getMeid();
             if ((id == null) || id.matches("^0*$")) {
                 loge("getDeviceId(): MEID is not initialized use ESN");
@@ -2063,7 +2084,8 @@
                 if (b != null) {
                     boolean broadcastEmergencyCallStateChanges = b.getBoolean(
                             CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
-                    logd("broadcastEmergencyCallStateChanges =" + broadcastEmergencyCallStateChanges);
+                    logd("broadcastEmergencyCallStateChanges = " +
+                            broadcastEmergencyCallStateChanges);
                     setBroadcastEmergencyCallStateChanges(broadcastEmergencyCallStateChanges);
                 } else {
                     loge("didn't get broadcastEmergencyCallStateChanges from carrier config");
@@ -2673,10 +2695,10 @@
         }
         // if phone is not in Ecm mode, and it's changed to Ecm mode
         if (mIsPhoneInEcmState == false) {
+            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
             mIsPhoneInEcmState = true;
             // notify change
             sendEmergencyCallbackModeChange();
-            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
 
             // Post this runnable so we will automatically exit
             // if no one invokes exitEmergencyCallbackMode() directly.
@@ -2703,15 +2725,16 @@
         }
         // if exiting ecm success
         if (ar.exception == null) {
+            if (mIsPhoneInEcmState) {
+                setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+                mIsPhoneInEcmState = false;
+            }
+
             // release wakeLock
             if (mWakeLock.isHeld()) {
                 mWakeLock.release();
             }
 
-            if (mIsPhoneInEcmState) {
-                mIsPhoneInEcmState = false;
-                setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
-            }
             // send an Intent
             sendEmergencyCallbackModeChange();
             // Re-initiate data connection
diff --git a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index b307a54..2a35370 100644
--- a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -22,7 +22,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.telephony.Rlog;
-import android.util.Log;
 
 import com.android.internal.telephony.uicc.AdnRecord;
 import com.android.internal.telephony.uicc.AdnRecordCache;
@@ -42,7 +41,6 @@
 public class IccPhoneBookInterfaceManager {
     static final String LOG_TAG = "IccPhoneBookIM";
     protected static final boolean DBG = true;
-    protected static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
 
     protected Phone mPhone;
     private   UiccCardApplication mCurrentApp = null;
@@ -174,9 +172,9 @@
 
 
         if (DBG) logd("updateAdnRecordsInEfBySearch: efid=0x" +
-                Integer.toHexString(efid).toUpperCase() + (VDBG ? " ("+ oldTag + "," +
-                oldPhoneNumber + ")" + "==>" + " ("+ newTag + ","
-                + newPhoneNumber + ")"+ " pin2=" + pin2 : ""));
+                Integer.toHexString(efid).toUpperCase() + " ("+ Rlog.pii(LOG_TAG, oldTag) + "," +
+                Rlog.pii(LOG_TAG, oldPhoneNumber) + ")" + "==>" + " ("+ Rlog.pii(LOG_TAG, newTag) +
+                "," + Rlog.pii(LOG_TAG, newPhoneNumber) + ")"+ " pin2=" + Rlog.pii(LOG_TAG, pin2));
 
         efid = updateEfForIccType(efid);
 
@@ -226,8 +224,9 @@
         }
 
         if (DBG) logd("updateAdnRecordsInEfByIndex: efid=0x" +
-                Integer.toHexString(efid).toUpperCase() + " Index=" + index +
-                (VDBG ? " ==> " + "(" + newTag + "," + newPhoneNumber + ")" + " pin2=" + pin2 : ""));
+                Integer.toHexString(efid).toUpperCase() + " Index=" + index + " ==> " + "(" +
+                Rlog.pii(LOG_TAG, newTag) + "," + Rlog.pii(LOG_TAG, newPhoneNumber) + ")" +
+                " pin2=" + Rlog.pii(LOG_TAG, pin2));
         synchronized(mLock) {
             checkThread();
             mSuccess = false;
diff --git a/src/java/com/android/internal/telephony/IccProvider.java b/src/java/com/android/internal/telephony/IccProvider.java
index 6d07698..222e1d6 100755
--- a/src/java/com/android/internal/telephony/IccProvider.java
+++ b/src/java/com/android/internal/telephony/IccProvider.java
@@ -29,7 +29,6 @@
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.telephony.Rlog;
-import android.util.Log;
 
 import java.util.List;
 
@@ -43,7 +42,6 @@
 public class IccProvider extends ContentProvider {
     private static final String TAG = "IccProvider";
     private static final boolean DBG = true;
-    private static final boolean VDBG = Rlog.isLoggable(TAG, Log.VERBOSE);
 
 
     private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
@@ -429,8 +427,8 @@
     addIccRecordToEf(int efType, String name, String number, String[] emails,
             String pin2, int subId) {
         if (DBG) log("addIccRecordToEf: efType=0x" + Integer.toHexString(efType).toUpperCase() +
-                (VDBG ? ", name=" + name + ", number=" + number + ", emails=" + emails : "") +
-                ", subscription=" + subId);
+                ", name=" + Rlog.pii(TAG, name) + ", number=" + Rlog.pii(TAG, number) +
+                ", emails=" + Rlog.pii(TAG, emails) + ", subscription=" + subId);
 
         boolean success = false;
 
@@ -459,8 +457,9 @@
     updateIccRecordInEf(int efType, String oldName, String oldNumber,
             String newName, String newNumber, String pin2, int subId) {
         if (DBG) log("updateIccRecordInEf: efType=0x" + Integer.toHexString(efType).toUpperCase() +
-                (VDBG ? ", oldname=" + oldName + ", oldnumber=" + oldNumber + ", newname=" +
-                        newName + ", newnumber=" + newName : "") + ", subscription=" + subId);
+                ", oldname=" + Rlog.pii(TAG, oldName) + ", oldnumber=" + Rlog.pii(TAG, oldNumber) +
+                ", newname=" + Rlog.pii(TAG, newName) + ", newnumber=" + Rlog.pii(TAG, newName) +
+                ", subscription=" + subId);
 
         boolean success = false;
 
@@ -484,8 +483,9 @@
     private boolean deleteIccRecordFromEf(int efType, String name, String number, String[] emails,
             String pin2, int subId) {
         if (DBG) log("deleteIccRecordFromEf: efType=0x" +
-                Integer.toHexString(efType).toUpperCase() + (VDBG ? ", name=" + name + ", number=" +
-                number + ", emails=" + emails + ", pin2=" + pin2 : "") + ", subscription=" + subId);
+                Integer.toHexString(efType).toUpperCase() + ", name=" + Rlog.pii(TAG, name) +
+                ", number=" + Rlog.pii(TAG, number) + ", emails=" + Rlog.pii(TAG, emails) +
+                ", pin2=" + Rlog.pii(TAG, pin2) + ", subscription=" + subId);
 
         boolean success = false;
 
@@ -517,7 +517,7 @@
             String alphaTag = record.getAlphaTag();
             String number = record.getNumber();
 
-            if (DBG) log("loadRecord: " + alphaTag + (VDBG ? ", " + number : ""));
+            if (DBG) log("loadRecord: " + alphaTag + ", " + Rlog.pii(TAG, number));
             contact[0] = alphaTag;
             contact[1] = number;
 
@@ -525,7 +525,7 @@
             if (emails != null) {
                 StringBuilder emailString = new StringBuilder();
                 for (String email: emails) {
-                    if (VDBG) log("Adding email:" + email);
+                    log("Adding email:" + Rlog.pii(TAG, email));
                     emailString.append(email);
                     emailString.append(",");
                 }
diff --git a/src/java/com/android/internal/telephony/MccTable.java b/src/java/com/android/internal/telephony/MccTable.java
index 2a531c4..1797e65 100644
--- a/src/java/com/android/internal/telephony/MccTable.java
+++ b/src/java/com/android/internal/telephony/MccTable.java
@@ -124,10 +124,17 @@
             return null;
         }
 
+        final String country = entry.mIso;
+
+        // Choose English as the default language for India.
+        if ("in".equals(country)) {
+            return "en";
+        }
+
         // Ask CLDR for the language this country uses...
-        Locale likelyLocale = ICU.addLikelySubtags(new Locale("und", entry.mIso));
+        Locale likelyLocale = ICU.addLikelySubtags(new Locale("und", country));
         String likelyLanguage = likelyLocale.getLanguage();
-        Slog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): country " + entry.mIso + " uses " +
+        Slog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): country " + country + " uses " +
                likelyLanguage);
         return likelyLanguage;
     }
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index bbecd9c..c01be85 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -23,6 +23,7 @@
 import android.content.SharedPreferences;
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
+import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
 import android.os.Build;
@@ -3321,6 +3322,15 @@
         mDcTracker.setPolicyDataEnabled(enabled);
     }
 
+    /**
+     * SIP URIs aliased to the current subscriber given by the IMS implementation.
+     * Applicable only on IMS; used in absence of line1number.
+     * @return array of SIP URIs aliased to the current subscriber
+     */
+    public Uri[] getCurrentSubscriberUris() {
+        return null;
+    }
+
     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/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java
index b782bc8..d582af0 100644
--- a/src/java/com/android/internal/telephony/RatRatcheter.java
+++ b/src/java/com/android/internal/telephony/RatRatcheter.java
@@ -22,6 +22,7 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
 import android.telephony.Rlog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -74,6 +75,19 @@
         }
     }
 
+    public void ratchetRat(ServiceState oldSS, ServiceState newSS) {
+        int newVoiceRat = ratchetRat(oldSS.getRilVoiceRadioTechnology(),
+                newSS.getRilVoiceRadioTechnology());
+        int newDataRat = ratchetRat(oldSS.getRilDataRadioTechnology(),
+                newSS.getRilDataRadioTechnology());
+        boolean newUsingCA = oldSS.isUsingCarrierAggregation() ||
+                newSS.isUsingCarrierAggregation();
+
+        newSS.setRilVoiceRadioTechnology(newVoiceRat);
+        newSS.setRilDataRadioTechnology(newDataRat);
+        newSS.setIsUsingCarrierAggregation(newUsingCA);
+    }
+
     private BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 54edc37..a919af2 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -952,7 +952,8 @@
                 }
                 // This will do nothing in the 'radio not available' case
                 setPowerStateToDesired();
-                pollState();
+                // These events are modem triggered, so pollState() needs to be forced
+                modemTriggeredPollState();
                 break;
 
             case EVENT_NETWORK_STATE_CHANGED:
@@ -2548,10 +2549,7 @@
         // ratchet the new tech up through it's rat family but don't drop back down
         // until cell change
         if (hasLocationChanged == false) {
-            mNewSS.setRilVoiceRadioTechnology(mRatRatcheter.ratchetRat(
-                    mSS.getRilVoiceRadioTechnology(), mNewSS.getRilVoiceRadioTechnology()));
-            mNewSS.setRilDataRadioTechnology(mRatRatcheter.ratchetRat(
-                    mSS.getRilDataRadioTechnology(), mNewSS.getRilDataRadioTechnology()));
+            mRatRatcheter.ratchetRat(mSS, mNewSS);
         }
 
         boolean hasRilVoiceRadioTechnologyChanged =
@@ -2794,6 +2792,14 @@
         boolean hasCdmaDataConnectionChanged =
                 mSS.getDataRegState() != mNewSS.getDataRegState();
 
+        boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
+
+        // ratchet the new tech up through it's rat family but don't drop back down
+        // until cell change
+        if (hasLocationChanged == false) {
+            mRatRatcheter.ratchetRat(mSS, mNewSS);
+        }
+
         boolean hasRilVoiceRadioTechnologyChanged =
                 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
 
@@ -2810,8 +2816,6 @@
 
         boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
 
-        boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
-
         TelephonyManager tm =
                 (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
 
@@ -2989,6 +2993,14 @@
         boolean hasCdmaDataConnectionChanged =
                 mSS.getDataRegState() != mNewSS.getDataRegState();
 
+        boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
+
+        // ratchet the new tech up through it's rat family but don't drop back down
+        // until cell change
+        if (hasLocationChanged == false) {
+            mRatRatcheter.ratchetRat(mSS, mNewSS);
+        }
+
         boolean hasVoiceRadioTechnologyChanged = mSS.getRilVoiceRadioTechnology()
                 != mNewSS.getRilVoiceRadioTechnology();
 
@@ -3005,8 +3017,6 @@
 
         boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
 
-        boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
-
         boolean has4gHandoff =
                 mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE &&
                 ((ServiceState.isLte(mSS.getRilDataRadioTechnology()) &&
diff --git a/src/java/com/android/internal/telephony/SmsApplication.java b/src/java/com/android/internal/telephony/SmsApplication.java
index 675d943..bf90350 100644
--- a/src/java/com/android/internal/telephony/SmsApplication.java
+++ b/src/java/com/android/internal/telephony/SmsApplication.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -74,7 +75,7 @@
         /**
          * Name of this SMS app for display.
          */
-        public String mApplicationName;
+        private String mApplicationName;
 
         /**
          * Package name for this SMS app.
@@ -125,16 +126,32 @@
                     && mRespondViaMessageClass != null && mSendToClass != null);
         }
 
-        public SmsApplicationData(String applicationName, String packageName, int uid) {
-            mApplicationName = applicationName;
+        public SmsApplicationData(String packageName, int uid) {
             mPackageName = packageName;
             mUid = uid;
         }
 
+        public String getApplicationName(Context context) {
+            if (mApplicationName == null) {
+                PackageManager pm = context.getPackageManager();
+                ApplicationInfo appInfo;
+                try {
+                    appInfo = pm.getApplicationInfoAsUser(mPackageName, 0,
+                            UserHandle.getUserId(mUid));
+                } catch (NameNotFoundException e) {
+                    return null;
+                }
+                if (appInfo != null) {
+                    CharSequence label  = pm.getApplicationLabel(appInfo);
+                    mApplicationName = (label == null) ? null : label.toString();
+                }
+            }
+            return mApplicationName;
+        }
+
         @Override
         public String toString() {
-            return "mApplicationName: " + mApplicationName +
-                    " mPackageName: " + mPackageName +
+            return " mPackageName: " + mPackageName +
                     " mSmsReceiverClass: " + mSmsReceiverClass +
                     " mMmsReceiverClass: " + mMmsReceiverClass +
                     " mRespondViaMessageClass: " + mRespondViaMessageClass +
@@ -217,9 +234,8 @@
             }
             final String packageName = activityInfo.packageName;
             if (!receivers.containsKey(packageName)) {
-                final String applicationName = resolveInfo.loadLabel(packageManager).toString();
-                final SmsApplicationData smsApplicationData = new SmsApplicationData(
-                        applicationName, packageName, activityInfo.applicationInfo.uid);
+                final SmsApplicationData smsApplicationData = new SmsApplicationData(packageName,
+                        activityInfo.applicationInfo.uid);
                 smsApplicationData.mSmsReceiverClass = activityInfo.name;
                 receivers.put(packageName, smsApplicationData);
             }
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index ea6fce8..a9553f6 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -147,7 +147,8 @@
                         throws RemoteException {
                     mCurrentlyActiveUserId = newUserId;
                     CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
-                            mPackageManager, TelephonyManager.getDefault(), mCurrentlyActiveUserId);
+                            mPackageManager, TelephonyManager.getDefault(),
+                            mContext.getContentResolver(), mCurrentlyActiveUserId);
 
                     if (reply != null) {
                         try {
@@ -172,7 +173,8 @@
             logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage());
         }
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
-                mPackageManager, TelephonyManager.getDefault(), mCurrentlyActiveUserId);
+                mPackageManager, TelephonyManager.getDefault(), mContext.getContentResolver(),
+                mCurrentlyActiveUserId);
     }
 
     private final BroadcastReceiver sReceiver = new  BroadcastReceiver() {
@@ -488,7 +490,8 @@
 
         // Update set of enabled carrier apps now that the privilege rules may have changed.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
-                mPackageManager, TelephonyManager.getDefault(), mCurrentlyActiveUserId);
+                mPackageManager, TelephonyManager.getDefault(), mContext.getContentResolver(),
+                mCurrentlyActiveUserId);
 
         broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
         updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
diff --git a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
index 055d574..ce991db 100644
--- a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
+++ b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
@@ -15,19 +15,18 @@
  */
 package com.android.internal.telephony;
 
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Bundle;
 import android.provider.VoicemailContract;
+import android.telephony.SmsMessage;
 import android.telephony.TelephonyManager;
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import android.util.Log;
 
-import android.telephony.SmsMessage;
-
 import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData;
 
+import java.nio.charset.StandardCharsets;
+
 public class VisualVoicemailSmsFilter {
 
     private static final String TAG = "VvmSmsFilter";
@@ -61,35 +60,50 @@
         // TODO: filter base on originating number and destination port.
 
         String messageBody = getFullMessage(pdus, format);
+
         if(messageBody == null){
+            // Verizon WAP push SMS is not recognized by android, which has a ascii PDU.
+            // Attempt to parse it.
+            Log.i(TAG, "Unparsable SMS received");
+            String asciiMessage = parseAsciiPduMessage(pdus);
+            WrappedMessageData messageData = VisualVoicemailSmsParser
+                .parseAlternativeFormat(asciiMessage);
+            if (messageData != null) {
+                sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData);
+            }
+            // Confidence for what the message actually is is low. Don't remove the message and let
+            // system decide. Usually because it is not parsable it will be dropped.
             return false;
+        } else {
+            String clientPrefix = settings.clientPrefix;
+            WrappedMessageData messageData = VisualVoicemailSmsParser
+                .parse(clientPrefix, messageBody);
+            if (messageData != null) {
+                sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData);
+                return true;
+            }
         }
-        String clientPrefix = settings.clientPrefix;
-
-        WrappedMessageData messageData = VisualVoicemailSmsParser.parse(clientPrefix, messageBody);
-        if (messageData != null) {
-            Log.i(TAG, "VVM SMS received");
-            Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
-            intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX, messageData.prefix);
-            intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS, messageData.fields);
-            intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID, subId);
-            intent.setPackage(vvmClientPackage);
-            context.sendBroadcast(intent);
-            return true;
-        }
-
         return false;
     }
 
+    private static void sendVvmSmsBroadcast(Context context, String vvmClientPackage, int subId,
+        WrappedMessageData messageData) {
+        Log.i(TAG, "VVM SMS received");
+        Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
+        intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX, messageData.prefix);
+        intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS, messageData.fields);
+        intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID, subId);
+        intent.setPackage(vvmClientPackage);
+        context.sendBroadcast(intent);
+    }
+
     private static String getFullMessage(byte[][] pdus, String format) {
         StringBuilder builder = new StringBuilder();
         for (byte pdu[] : pdus) {
             SmsMessage message =SmsMessage.createFromPdu(pdu, format);
 
-            if(message == null || message.mWrappedSmsMessage == null) {
-                // b/29123941 Certain PDU will cause createFromPdu() to return a SmsMessage with
-                // null mWrappedSmsMessage, throwing NPE on any method called. In this case, just
-                // ignore the message.
+            if (message == null) {
+                // The PDU is not recognized by android
                 return null;
             }
             String body = message.getMessageBody();
@@ -99,4 +113,12 @@
         }
         return builder.toString();
     }
+
+    private static String parseAsciiPduMessage(byte[][] pdus) {
+        StringBuilder builder = new StringBuilder();
+        for (byte pdu[] : pdus) {
+            builder.append(new String(pdu, StandardCharsets.US_ASCII));
+        }
+        return builder.toString();
+    }
 }
diff --git a/src/java/com/android/internal/telephony/VisualVoicemailSmsParser.java b/src/java/com/android/internal/telephony/VisualVoicemailSmsParser.java
index 0de37d5..b6b3202 100644
--- a/src/java/com/android/internal/telephony/VisualVoicemailSmsParser.java
+++ b/src/java/com/android/internal/telephony/VisualVoicemailSmsParser.java
@@ -20,6 +20,10 @@
 
 public class VisualVoicemailSmsParser {
 
+    private static final String[] ALLOWED_ALTERNATIVE_FORMAT_EVENT = new String[] {
+            "MBOXUPDATE", "UNRECOGNIZED"
+    };
+
     /**
      * Class wrapping the raw OMTP message data, internally represented as as map of all key-value
      * pairs found in the SMS body. <p> All the methods return null if either the field was not
@@ -80,6 +84,7 @@
      * @param message The sms string with the prefix removed.
      * @return A WrappedMessageData object containing the map.
      */
+    @Nullable
     private static Bundle parseSmsBody(String message) {
         // TODO: ensure fail if format does not match
         Bundle keyValues = new Bundle();
@@ -107,4 +112,42 @@
 
         return keyValues;
     }
+
+    /**
+     * The alternative format is [Event]?([key]=[value])*, for example
+     *
+     * <p>"MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=foo".
+     *
+     * <p>This format is not protected with a client prefix and should be handled with care. For
+     * safety, the event type must be one of {@link #ALLOWED_ALTERNATIVE_FORMAT_EVENT}
+     */
+    @Nullable
+    public static WrappedMessageData parseAlternativeFormat(String smsBody) {
+        try {
+            int eventTypeEnd = smsBody.indexOf("?");
+            if (eventTypeEnd == -1) {
+                return null;
+            }
+            String eventType = smsBody.substring(0, eventTypeEnd);
+            if (!isAllowedAlternativeFormatEvent(eventType)) {
+                return null;
+            }
+            Bundle fields = parseSmsBody(smsBody.substring(eventTypeEnd + 1));
+            if (fields == null) {
+                return null;
+            }
+            return new WrappedMessageData(eventType, fields);
+        } catch (IndexOutOfBoundsException e) {
+            return null;
+        }
+    }
+
+    private static boolean isAllowedAlternativeFormatEvent(String eventType) {
+        for (String event : ALLOWED_ALTERNATIVE_FORMAT_EVENT) {
+            if (event.equals(eventType)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 89c1522..1de72db 100644
--- a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -22,7 +22,6 @@
 import android.telephony.cdma.CdmaSmsCbProgramResults;
 import android.text.format.Time;
 import android.telephony.Rlog;
-import android.util.Log;
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
@@ -436,8 +435,7 @@
         builder.append(", readAckReq=" + readAckReq);
         builder.append(", reportReq=" + reportReq);
         builder.append(", numberOfMessages=" + numberOfMessages);
-        builder.append(", callbackNumber=" +
-                (Rlog.isLoggable(LOG_TAG, Log.DEBUG) ? callbackNumber : "XXX"));
+        builder.append(", callbackNumber=" + Rlog.pii(LOG_TAG, callbackNumber));
         builder.append(", depositIndex=" + depositIndex);
         builder.append(", hasUserDataHeader=" + hasUserDataHeader);
         builder.append(", userData=" + userData);
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index 12c3945..7865bc4 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -450,9 +450,14 @@
         }
     }
 
-    public boolean hasNoRestrictedRequests() {
+    public boolean hasNoRestrictedRequests(boolean excludeDun) {
         synchronized (mRefCountLock) {
             for (NetworkRequest nr : mNetworkRequests) {
+                if (excludeDun &&
+                        nr.networkCapabilities.hasCapability(
+                        NetworkCapabilities.NET_CAPABILITY_DUN)) {
+                    continue;
+                }
                 if (nr.networkCapabilities.hasCapability(
                         NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) {
                     return false;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index c1319a4..0919af1 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -760,6 +760,11 @@
 
     private void updateTcpBufferSizes(int rilRat) {
         String sizes = null;
+        if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA) {
+            // for now treat CA as LTE.  Plan to surface the extra bandwith in a more
+            // precise manner which should affect buffer sizes
+            rilRat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+        }
         String ratName = ServiceState.rilRadioTechnologyToString(rilRat).toLowerCase(Locale.ROOT);
         // ServiceState gives slightly different names for EVDO tech ("evdo-rev.0" for ex)
         // - patch it up:
@@ -860,7 +865,7 @@
         // first, if we have no restricted requests, this override can stay FALSE:
         boolean noRestrictedRequests = true;
         for (ApnContext apnContext : mApnContexts.keySet()) {
-            noRestrictedRequests &= apnContext.hasNoRestrictedRequests();
+            noRestrictedRequests &= apnContext.hasNoRestrictedRequests(true /* exclude DUN */);
         }
         if (noRestrictedRequests) {
             return;
@@ -948,6 +953,8 @@
         }
         if (mRestrictedNetworkOverride) {
             result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+            // don't use dun on restriction-overriden networks.
+            result.removeCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
         }
 
         int up = 14;
@@ -2055,7 +2062,8 @@
                 + " mLastFailCause=" + mLastFailCause
                 + " mTag=" + mTag
                 + " mLinkProperties=" + mLinkProperties
-                + " linkCapabilities=" + makeNetworkCapabilities();
+                + " linkCapabilities=" + makeNetworkCapabilities()
+                + " mRestrictedNetworkOverride=" + mRestrictedNetworkOverride;
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 25b82ef..11e8cc1 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -1514,10 +1514,12 @@
         // request for the network.
         // TODO - may want restricted requests to only apply to carrier-limited data access
         //        rather than applying to user limited as well.
+        // Exclude DUN for the purposes of the override until we get finer grained
+        // intention in NetworkRequests
         boolean checkUserDataEnabled =
                 ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
                         mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) &&
-                apnContext.hasNoRestrictedRequests();
+                apnContext.hasNoRestrictedRequests(true /*exclude DUN */);
 
         DataAllowFailReason failureReason = new DataAllowFailReason();
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsExternalCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsExternalCallTracker.java
index a1a73e4..4bea73d 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsExternalCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsExternalCallTracker.java
@@ -88,7 +88,8 @@
                 Log.e(TAG, "onPullExternalCall : No call puller defined");
                 return;
             }
-            mCallPuller.pullExternalCall(connection.getAddress(), connection.getVideoState());
+            mCallPuller.pullExternalCall(connection.getAddress(), connection.getVideoState(),
+                    connection.getCallId());
         }
     }
 
@@ -324,7 +325,7 @@
 
         // Add to list of tracked connections.
         mExternalConnections.put(connection.getCallId(), connection);
-        mExternalCallPullableState.put(connection.getCallId(), isCallPullPermitted);
+        mExternalCallPullableState.put(connection.getCallId(), state.isCallPullable());
 
         // Note: The notification of unknown connection is ultimately handled by
         // PstnIncomingCallNotifier#addNewUnknownCall.  That method will ensure that an extra is set
@@ -365,9 +366,11 @@
             connection.setVideoState(newVideoState);
         }
 
+        mExternalCallPullableState.put(state.getCallId(), state.isCallPullable());
         boolean isCallPullPermitted = isCallPullPermitted(state.isCallPullable(), newVideoState);
         Log.d(TAG,
-                "updateExistingConnection - pullable state : externalCallId = " + connection.getCallId()
+                "updateExistingConnection - pullable state : externalCallId = " + connection
+                        .getCallId()
                         + " ; isPullable = " + isCallPullPermitted
                         + " ; networkPullable = " + state.isCallPullable()
                         + " ; isVideo = "
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 030643f..0cfe257 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -24,6 +24,7 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
@@ -156,6 +157,17 @@
         }
     };
 
+    private Uri[] mCurrentSubscriberUris;
+
+    protected void setCurrentSubscriberUris(Uri[] currentSubscriberUris) {
+        this.mCurrentSubscriberUris = currentSubscriberUris;
+    }
+
+    @Override
+    public Uri[] getCurrentSubscriberUris() {
+        return mCurrentSubscriberUris;
+    }
+
     // Create Cf (Call forward) so that dialling number &
     // mIsCfu (true if reason is call forward unconditional)
     // mOnComplete (Message object passed by client) can be packed &
@@ -1293,10 +1305,10 @@
         }
         // if phone is not in Ecm mode, and it's changed to Ecm mode
         if (mIsPhoneInEcmState == false) {
+            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
             mIsPhoneInEcmState = true;
             // notify change
             sendEmergencyCallbackModeChange();
-            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
 
             // Post this runnable so we will automatically exit
             // if no one invokes exitEmergencyCallbackMode() directly.
@@ -1313,6 +1325,12 @@
             Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode: mIsPhoneInEcmState = "
                     + mIsPhoneInEcmState);
         }
+
+        if (mIsPhoneInEcmState) {
+            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+            mIsPhoneInEcmState = false;
+        }
+
         // Remove pending exit Ecm runnable, if any
         removeCallbacks(mExitEcmRunnable);
 
@@ -1325,10 +1343,6 @@
             mWakeLock.release();
         }
 
-        if (mIsPhoneInEcmState) {
-            mIsPhoneInEcmState = false;
-            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
-        }
         // send an Intent
         sendEmergencyCallbackModeChange();
     }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 897b374..d3de950 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
@@ -195,9 +196,15 @@
     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 EVENT_GET_IMS_SERVICE = 24;
 
     private static final int TIMEOUT_HANGUP_PENDINGMO = 500;
 
+    // The number of times we will try to connect to the ImsService before giving up.
+    private static final int NUM_IMS_SERVICE_RETRIES = 10;
+    // The number of milliseconds in between each try.
+    private static final int TIME_BETWEEN_IMS_SERVICE_RETRIES_MS = 400; // ms
+
     //***** Instance Variables
     private ArrayList<ImsPhoneConnection> mConnections = new ArrayList<ImsPhoneConnection>();
     private RegistrantList mVoiceCallEndedRegistrants = new RegistrantList();
@@ -230,6 +237,7 @@
 
     private PhoneConstants.State mState = PhoneConstants.State.IDLE;
 
+    private int mImsServiceRetryCount;
     private ImsManager mImsManager;
     private int mServiceId = -1;
 
@@ -297,12 +305,10 @@
         mPhone.getDefaultPhone().registerForDataEnabledChanged(
                 this, EVENT_DATA_ENABLED_CHANGED, null);
 
-        Thread t = new Thread() {
-            public void run() {
-                getImsService();
-            }
-        };
-        t.start();
+        mImsServiceRetryCount = 0;
+        // Send a message to connect to the Ims Service and open a connection through
+        // getImsService().
+        sendEmptyMessage(EVENT_GET_IMS_SERVICE);
     }
 
     private PendingIntent createIncomingCallPendingIntent() {
@@ -312,37 +318,31 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
-    private void getImsService() {
+    private void getImsService() throws ImsException {
         if (DBG) log("getImsService");
         mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());
-        try {
-            mServiceId = mImsManager.open(ImsServiceClass.MMTEL,
-                    createIncomingCallPendingIntent(),
-                    mImsConnectionStateListener);
+        mServiceId = mImsManager.open(ImsServiceClass.MMTEL,
+                createIncomingCallPendingIntent(),
+                mImsConnectionStateListener);
 
-            mImsManager.setImsConfigListener(mImsConfigListener);
+        mImsManager.setImsConfigListener(mImsConfigListener);
 
-            // Get the ECBM interface and set IMSPhone's listener object for notifications
-            getEcbmInterface().setEcbmStateListener(mPhone.getImsEcbmStateListener());
-            if (mPhone.isInEcm()) {
-                // Call exit ECBM which will invoke onECBMExited
-                mPhone.exitEmergencyCallbackMode();
-            }
-            int mPreferredTtyMode = Settings.Secure.getInt(
-                mPhone.getContext().getContentResolver(),
-                Settings.Secure.PREFERRED_TTY_MODE,
-                Phone.TTY_MODE_OFF);
-            mImsManager.setUiTTYMode(mPhone.getContext(), mServiceId, mPreferredTtyMode, null);
+        // Get the ECBM interface and set IMSPhone's listener object for notifications
+        getEcbmInterface().setEcbmStateListener(mPhone.getImsEcbmStateListener());
+        if (mPhone.isInEcm()) {
+            // Call exit ECBM which will invoke onECBMExited
+            mPhone.exitEmergencyCallbackMode();
+        }
+        int mPreferredTtyMode = Settings.Secure.getInt(
+            mPhone.getContext().getContentResolver(),
+            Settings.Secure.PREFERRED_TTY_MODE,
+            Phone.TTY_MODE_OFF);
+        mImsManager.setUiTTYMode(mPhone.getContext(), mServiceId, mPreferredTtyMode, null);
 
-            ImsMultiEndpoint multiEndpoint = getMultiEndpointInterface();
-            if (multiEndpoint != null) {
-                multiEndpoint.setExternalCallStateListener(
-                        mPhone.getExternalCallTracker().getExternalCallStateListener());
-            }
-        } catch (ImsException e) {
-            loge("getImsService: " + e);
-            //Leave mImsManager as null, then CallStateException will be thrown when dialing
-            mImsManager = null;
+        ImsMultiEndpoint multiEndpoint = getMultiEndpointInterface();
+        if (multiEndpoint != null) {
+            multiEndpoint.setExternalCallStateListener(
+                    mPhone.getExternalCallTracker().getExternalCallStateListener());
         }
     }
 
@@ -356,6 +356,7 @@
         clearDisconnected();
         mPhone.getContext().unregisterReceiver(mReceiver);
         mPhone.unregisterForDataEnabledChanged(this);
+        removeMessages(EVENT_GET_IMS_SERVICE);
     }
 
     @Override
@@ -609,7 +610,10 @@
                 if (intentExtras.containsKey(ImsCallProfile.EXTRA_IS_CALL_PULL)) {
                     profile.mCallExtras.putBoolean(ImsCallProfile.EXTRA_IS_CALL_PULL,
                             intentExtras.getBoolean(ImsCallProfile.EXTRA_IS_CALL_PULL));
+                    int dialogId = intentExtras.getInt(
+                            ImsExternalCallTracker.EXTRA_IMS_EXTERNAL_CALL_ID);
                     conn.setIsPulledCall(true);
+                    conn.setPulledDialogId(dialogId);
                 }
 
                 // Pack the OEM-specific call extras.
@@ -1448,6 +1452,15 @@
             ImsPhoneConnection conn = findConnection(imsCall);
             if (DBG) log("cause = " + cause + " conn = " + conn);
 
+            if (conn != null) {
+                android.telecom.Connection.VideoProvider videoProvider = conn.getVideoProvider();
+                if (videoProvider instanceof ImsVideoCallProviderWrapper) {
+                    ImsVideoCallProviderWrapper wrapper = (ImsVideoCallProviderWrapper)
+                            videoProvider;
+
+                    wrapper.removeImsVideoProviderCallback(conn);
+                }
+            }
             if (mOnHoldToneId == System.identityHashCode(conn)) {
                 if (conn != null && mOnHoldToneStarted) {
                     mPhone.stopOnHoldTone(conn);
@@ -1455,17 +1468,33 @@
                 mOnHoldToneStarted = false;
                 mOnHoldToneId = -1;
             }
-            if (conn != null && conn.isIncoming() && conn.getConnectTime() == 0
-                    && cause != DisconnectCause.ANSWERED_ELSEWHERE) {
-                // Missed
-                if (cause == DisconnectCause.NORMAL) {
-                    cause = DisconnectCause.INCOMING_MISSED;
-                } else {
-                    cause = DisconnectCause.INCOMING_REJECTED;
-                }
-                if (DBG) log("Incoming connection of 0 connect time detected - translated cause = "
-                        + cause);
+            if (conn != null) {
+                if (conn.isPulledCall() && (
+                        reasonInfo.getCode() == ImsReasonInfo.CODE_CALL_PULL_OUT_OF_SYNC ||
+                        reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_TEMPRARILY_UNAVAILABLE) &&
+                        mPhone != null && mPhone.getExternalCallTracker() != null) {
 
+                    log("Call pull failed.");
+                    // Call was being pulled, but the call pull has failed -- inform the associated
+                    // TelephonyConnection that the pull failed, and provide it with the original
+                    // external connection which was pulled so that it can be swapped back.
+                    conn.onCallPullFailed(mPhone.getExternalCallTracker()
+                            .getConnectionById(conn.getPulledDialogId()));
+                    // Do not mark as disconnected; the call will just change from being a regular
+                    // call to being an external call again.
+                    cause = DisconnectCause.NOT_DISCONNECTED;
+
+                } else if (conn.isIncoming() && conn.getConnectTime() == 0
+                        && cause != DisconnectCause.ANSWERED_ELSEWHERE) {
+                    // Missed
+                    if (cause == DisconnectCause.NORMAL) {
+                        cause = DisconnectCause.INCOMING_MISSED;
+                    } else {
+                        cause = DisconnectCause.INCOMING_REJECTED;
+                    }
+                    if (DBG) log("Incoming connection of 0 connect time detected - translated " +
+                            "cause = " + cause);
+                }
             }
 
             if (cause == DisconnectCause.NORMAL && conn != null && conn.getImsCall().isMerged()) {
@@ -2004,6 +2033,12 @@
             if (DBG) log("onVoiceMessageCountChanged :: count=" + count);
             mPhone.mDefaultPhone.setVoiceMessageCount(count);
         }
+
+        @Override
+        public void registrationAssociatedUriChanged(Uri[] uris) {
+            if (DBG) log("registrationAssociatedUriChanged");
+            mPhone.setCurrentSubscriberUris(uris);
+        }
     };
 
     private ImsConfigListener.Stub mImsConfigListener = new ImsConfigListener.Stub() {
@@ -2153,6 +2188,27 @@
                     onDataEnabledChanged(p.first, p.second);
                 }
                 break;
+            case EVENT_GET_IMS_SERVICE:
+                try {
+                    getImsService();
+                } catch (ImsException e) {
+                    loge("getImsService: " + e);
+                    //Leave mImsManager as null, then CallStateException will be thrown when dialing
+                    mImsManager = null;
+                    if (mImsServiceRetryCount < NUM_IMS_SERVICE_RETRIES) {
+                        loge("getImsService: Retrying getting ImsService...");
+                        sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE,
+                                TIME_BETWEEN_IMS_SERVICE_RETRIES_MS);
+                        mImsServiceRetryCount++;
+                    } else {
+                        // We have been unable to connect for
+                        // NUM_IMS_SERVICE_RETRIES*TIME_BETWEEN_IMS_SERVICE_RETRIES_MS ms. We will
+                        // probably never be able to connect, so we should just give up.
+                        loge("getImsService: ImsService retrieval timeout... ImsService is " +
+                                "unavailable.");
+                    }
+                }
+                break;
         }
     }
 
@@ -2299,6 +2355,7 @@
             conn.setVideoProvider(imsVideoCallProviderWrapper);
             imsVideoCallProviderWrapper.registerForDataUsageUpdate
                     (this, EVENT_VT_DATA_USAGE_UPDATE, imsCall);
+            imsVideoCallProviderWrapper.addImsVideoProviderCallback(conn);
         }
     }
 
@@ -2383,11 +2440,14 @@
      *
      * @param number The phone number of the call to be pulled.
      * @param videoState The desired video state of the pulled call.
+     * @param dialogId The {@link ImsExternalConnection#getCallId()} dialog id associated with the
+     *                 call which is being pulled.
      */
     @Override
-    public void pullExternalCall(String number, int videoState) {
+    public void pullExternalCall(String number, int videoState, int dialogId) {
         Bundle extras = new Bundle();
         extras.putBoolean(ImsCallProfile.EXTRA_IS_CALL_PULL, true);
+        extras.putInt(ImsExternalCallTracker.EXTRA_IMS_EXTERNAL_CALL_ID, dialogId);
         try {
             Connection connection = dial(number, videoState, extras);
             mPhone.notifyUnknownConnection(connection);
@@ -2423,9 +2483,15 @@
         boolean isActiveCallVideo = activeCall.isVideoCall() ||
                 (mTreatDowngradedVideoCallsAsVideoCalls && activeCall.wasVideoCall());
         boolean isActiveCallOnWifi = activeCall.isWifiCall();
+        boolean isVoWifiEnabled = mImsManager.isWfcEnabledByPlatform(mPhone.getContext()) &&
+                mImsManager.isWfcEnabledByUser(mPhone.getContext());
         boolean isIncomingCallAudio = !incomingCall.isVideoCall();
 
-        return isActiveCallVideo && isActiveCallOnWifi && isIncomingCallAudio;
+        log("shouldDisconnectActiveCallOnAnswer : isActiveCallVideo=" + isActiveCallVideo +
+                " isActiveCallOnWifi=" + isActiveCallOnWifi + " isIncomingCallAudio=" +
+                isIncomingCallAudio + " isVowifiEnabled=" + isVoWifiEnabled);
+
+        return isActiveCallVideo && isActiveCallOnWifi && isIncomingCallAudio && !isVoWifiEnabled;
     }
 
     /** Get aggregated video call data usage since boot.
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index d517bb1..7462daa 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -27,7 +27,7 @@
 import android.os.PowerManager;
 import android.os.Registrant;
 import android.os.SystemClock;
-import android.telecom.Log;
+import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
@@ -37,6 +37,7 @@
 
 import com.android.ims.ImsException;
 import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.internal.ImsVideoCallProviderWrapper;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
@@ -51,7 +52,9 @@
 /**
  * {@hide}
  */
-public class ImsPhoneConnection extends Connection {
+public class ImsPhoneConnection extends Connection implements
+        ImsVideoCallProviderWrapper.ImsVideoProviderWrapperCallback {
+
     private static final String LOG_TAG = "ImsPhoneConnection";
     private static final boolean DBG = true;
 
@@ -89,6 +92,15 @@
     private boolean mIsEmergency = false;
 
     /**
+     * Used to indicate that video state changes detected by
+     * {@link #updateMediaCapabilities(ImsCall)} should be ignored.  When a video state change from
+     * unpaused to paused occurs, we set this flag and then update the existing video state when
+     * new {@link #onReceiveSessionModifyResponse(int, VideoProfile, VideoProfile)} callbacks come
+     * in.  When the video un-pauses we continue receiving the video state updates.
+     */
+    private boolean mShouldIgnoreVideoStateChanges = false;
+
+    /**
      * Used to indicate whether the wifi state is based on
      * {@link com.android.ims.ImsConnectionStateListener#
      *      onFeatureCapabilityChanged(int, int[], int[])} callbacks, or values received via the
@@ -379,7 +391,9 @@
     @Override
     public boolean onDisconnect(int cause) {
         Rlog.d(LOG_TAG, "onDisconnect: cause=" + cause);
-        if (mCause != DisconnectCause.LOCAL) mCause = cause;
+        if (mCause != DisconnectCause.LOCAL || cause == DisconnectCause.INCOMING_REJECTED) {
+            mCause = cause;
+        }
         return onDisconnect();
     }
 
@@ -740,7 +754,7 @@
             int namep = ImsCallProfile.OIRToPresentation(
                     callProfile.getCallExtraInt(ImsCallProfile.EXTRA_CNAP));
             if (Phone.DEBUG_PHONE) {
-                Rlog.d(LOG_TAG, "address = " +  address + " name = " + name +
+                Rlog.d(LOG_TAG, "address = " + Rlog.pii(LOG_TAG, address) + " name = " + name +
                         " nump = " + nump + " namep = " + namep);
             }
             if(equalsHandlesNulls(mAddress, address)) {
@@ -792,8 +806,35 @@
                         .getVideoStateFromImsCallProfile(negotiatedCallProfile);
 
                 if (oldVideoState != newVideoState) {
-                    setVideoState(newVideoState);
-                    changed = true;
+                    // The video state has changed.  See also code in onReceiveSessionModifyResponse
+                    // below.  When the video enters a paused state, subsequent changes to the video
+                    // state will not be reported by the modem.  In onReceiveSessionModifyResponse
+                    // we will be updating the current video state while paused to include any
+                    // changes the modem reports via the video provider.  When the video enters an
+                    // unpaused state, we will resume passing the video states from the modem as is.
+                    if (VideoProfile.isPaused(oldVideoState) &&
+                            !VideoProfile.isPaused(newVideoState)) {
+                        // Video entered un-paused state; recognize updates from now on; we want to
+                        // ensure that the new un-paused state is propagated to Telecom, so change
+                        // this now.
+                        mShouldIgnoreVideoStateChanges = false;
+                    }
+
+                    if (!mShouldIgnoreVideoStateChanges) {
+                        setVideoState(newVideoState);
+                        changed = true;
+                    } else {
+                        Rlog.d(LOG_TAG, "updateMediaCapabilities - ignoring video state change " +
+                                "due to paused state.");
+                    }
+
+                    if (!VideoProfile.isPaused(oldVideoState) &&
+                            VideoProfile.isPaused(newVideoState)) {
+                        // Video entered pause state; ignore updates until un-paused.  We do this
+                        // after setVideoState is called above to ensure Telecom is notified that
+                        // the device has entered paused state.
+                        mShouldIgnoreVideoStateChanges = true;
+                    }
                 }
             }
 
@@ -982,7 +1023,7 @@
         sb.append(" telecomCallID: ");
         sb.append(getTelecomCallId());
         sb.append(" address: ");
-        sb.append(Log.pii(getAddress()));
+        sb.append(Rlog.pii(LOG_TAG, getAddress()));
         sb.append(" ImsCall: ");
         if (mImsCall == null) {
             sb.append("null");
@@ -1000,4 +1041,48 @@
     protected boolean isEmergency() {
         return mIsEmergency;
     }
+
+    /**
+     * Handles notifications from the {@link ImsVideoCallProviderWrapper} of session modification
+     * responses received.
+     *
+     * @param status The status of the original request.
+     * @param requestProfile The requested video profile.
+     * @param responseProfile The response upon video profile.
+     */
+    @Override
+    public void onReceiveSessionModifyResponse(int status, VideoProfile requestProfile,
+            VideoProfile responseProfile) {
+        if (status == android.telecom.Connection.VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS &&
+                mShouldIgnoreVideoStateChanges) {
+            int currentVideoState = getVideoState();
+            int newVideoState = responseProfile.getVideoState();
+
+            // If the current video state is paused, the modem will not send us any changes to
+            // the TX and RX bits of the video state.  Until the video is un-paused we will
+            // "fake out" the video state by applying the changes that the modem reports via a
+            // response.
+
+            // First, find out whether there was a change to the TX or RX bits:
+            int changedBits = currentVideoState ^ newVideoState;
+            changedBits &= VideoProfile.STATE_BIDIRECTIONAL;
+            if (changedBits == 0) {
+                // No applicable change, bail out.
+                return;
+            }
+
+            // Turn off any existing bits that changed.
+            currentVideoState &= ~(changedBits & currentVideoState);
+            // Turn on any new bits that turned on.
+            currentVideoState |= changedBits & newVideoState;
+
+            Rlog.d(LOG_TAG, "onReceiveSessionModifyResponse : received " +
+                    VideoProfile.videoStateToString(requestProfile.getVideoState()) +
+                    " / " +
+                    VideoProfile.videoStateToString(responseProfile.getVideoState()) +
+                    " while paused ; sending new videoState = " +
+                    VideoProfile.videoStateToString(currentVideoState));
+            setVideoState(currentVideoState);
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPullCall.java b/src/java/com/android/internal/telephony/imsphone/ImsPullCall.java
index 793fb0b..dbb4036 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPullCall.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPullCall.java
@@ -31,6 +31,8 @@
      *
      * @param number The phone number of the call to be pulled.
      * @param videoState The video state of the call to be pulled.
+     * @param dialogId The {@link ImsExternalConnection#getCallId()} dialog Id associated with the
+     *                 call to be pulled.
      */
-    void pullExternalCall(String number, int videoState);
+    void pullExternalCall(String number, int videoState, int dialogId);
 }
diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
index db29bc4..d943148 100644
--- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
@@ -541,7 +541,7 @@
 
         try {
             if (validEfCfis(mEfCfis)) {
-                // lsb is of byte 1 is voice status
+                // lsb is of byte f1 is voice status
                 if (enable) {
                     mEfCfis[1] |= 1;
                 } else {
@@ -554,9 +554,7 @@
                 // Update dialNumber if not empty and CFU is enabled.
                 // Spec reference for EF_CFIS contents, TS 51.011 section 10.3.46.
                 if (enable && !TextUtils.isEmpty(dialNumber)) {
-                    if (VDBG) {
-                        logv("EF_CFIS: updating cf number, " + dialNumber);
-                    }
+                    logv("EF_CFIS: updating cf number, " + Rlog.pii(LOG_TAG, dialNumber));
                     byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(dialNumber);
 
                     System.arraycopy(bcdNumber, 0, mEfCfis, CFIS_TON_NPI_OFFSET, bcdNumber.length);
@@ -674,7 +672,7 @@
                 }
 
                 log("IMSI: mMncLength=" + mMncLength);
-                log("IMSI: " + mImsi.substring(0, 6) + "xxxxxxx");
+                log("IMSI: " + mImsi.substring(0, 6) + Rlog.pii(LOG_TAG, mImsi.substring(6)));
 
                 if (((mMncLength == UNKNOWN) || (mMncLength == 2)) &&
                         ((mImsi != null) && (mImsi.length() >= 6))) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
index da1f1c8..9974a6d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
@@ -19,23 +19,40 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.test.InstrumentationTestCase;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
 
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class CarrierAppUtilsTest extends InstrumentationTestCase {
     private static final String CARRIER_APP = "com.example.carrier";
     private static final String[] CARRIER_APPS = new String[] { CARRIER_APP };
+    private static final String ASSOCIATED_APP = "com.example.associated";
+    private static final ArrayMap<String, List<String>> ASSOCIATED_APPS = new ArrayMap<>();
+    static {
+        List<String> associatedAppList = new ArrayList<>();
+        associatedAppList.add(ASSOCIATED_APP);
+        ASSOCIATED_APPS.put(CARRIER_APP, associatedAppList);
+    }
     private static final int USER_ID = 12345;
     private static final String CALLING_PACKAGE = "phone";
 
     @Mock private IPackageManager mPackageManager;
     @Mock private TelephonyManager mTelephonyManager;
+    private SettingsMockContentProvider mContentProvider;
+    private MockContentResolver mContentResolver;
 
     @Override
     public void setUp() throws Exception {
@@ -44,13 +61,20 @@
                 getInstrumentation().getTargetContext().getCacheDir().getPath());
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
         MockitoAnnotations.initMocks(this);
+
+        mContentResolver = new MockContentResolver();
+        mContentProvider = new SettingsMockContentProvider();
+        mContentResolver.addProvider(Settings.AUTHORITY, mContentProvider);
+        Settings.Secure.putIntForUser(
+                mContentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0, USER_ID);
     }
 
     /** No apps configured - should do nothing. */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_EmptyList() {
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, new String[0]);
+                mTelephonyManager, mContentResolver, USER_ID, new String[0],
+                ASSOCIATED_APPS);
         Mockito.verifyNoMoreInteractions(mPackageManager, mTelephonyManager);
     }
 
@@ -58,9 +82,10 @@
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_MissingApp() throws Exception {
         Mockito.when(mPackageManager.getApplicationInfo("com.example.missing.app",
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(null);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(null);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, new String[] { "com.example.missing.app" });
+                mTelephonyManager, mContentResolver, USER_ID,
+                new String[] { "com.example.missing.app" }, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -75,9 +100,9 @@
     public void testDisableCarrierAppsUntilPrivileged_NonSystemApp() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -99,11 +124,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -119,11 +144,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -139,11 +164,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -159,11 +184,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -171,43 +196,139 @@
                 new String[] {appInfo.packageName}, USER_ID);
     }
 
-    /** Configured app has privileges, and is in the default state - should enable. */
+    /**
+     * Configured app has privileges, and is in the default state - should enable. Associated app
+     * is missing and should not be touched.
+     */
     @Test @SmallTest
-    public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_Default() throws Exception {
+    public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_MissingAssociated_Default()
+            throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager).setApplicationEnabledSetting(
                 CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                 PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
+                ASSOCIATED_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
         Mockito.verify(mPackageManager).grantDefaultPermissionsToEnabledCarrierApps(
                 new String[] {appInfo.packageName}, USER_ID);
     }
 
-    /** Configured app has privileges, and is disabled until used - should enable. */
+    /**
+     * Configured app has privileges, and is in the default state along with associated app - should
+     * enable both.
+     */
     @Test @SmallTest
-    public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_DisabledUntilUsed()
+    public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_Associated_Default()
+            throws Exception {
+        // Enabling should be done even if this isn't the first run.
+        Settings.Secure.putIntForUser(
+                mContentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1, USER_ID);
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
+        appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(appInfo);
+        ApplicationInfo associatedAppInfo = new ApplicationInfo();
+        associatedAppInfo.packageName = ASSOCIATED_APP;
+        associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(associatedAppInfo);
+        Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
+                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
+        Mockito.verify(mPackageManager).setApplicationEnabledSetting(
+                CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager).setApplicationEnabledSetting(
+                ASSOCIATED_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager).grantDefaultPermissionsToEnabledCarrierApps(
+                new String[] {appInfo.packageName}, USER_ID);
+    }
+
+    /**
+     * Configured app has privileges, and is disabled until used - should enable. Associated app has
+     * been updated and should not be touched.
+     */
+    @Test @SmallTest
+    public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_UpdatedAssociated_DisabledUntilUsed()
             throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+        ApplicationInfo associatedAppInfo = new ApplicationInfo();
+        associatedAppInfo.packageName = ASSOCIATED_APP;
+        associatedAppInfo.flags |=
+                ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+        associatedAppInfo.enabledSetting =
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager).setApplicationEnabledSetting(
                 CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                 PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
+                ASSOCIATED_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager).grantDefaultPermissionsToEnabledCarrierApps(
+                new String[] {appInfo.packageName}, USER_ID);
+    }
+
+    /**
+     * Configured app has privileges, and is disabled until used along with associated app - should
+     * enable both.
+     */
+    @Test @SmallTest
+    public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_Associated_DisabledUntilUsed()
+            throws Exception {
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
+        appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+        ApplicationInfo associatedAppInfo = new ApplicationInfo();
+        associatedAppInfo.packageName = ASSOCIATED_APP;
+        associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        associatedAppInfo.enabledSetting =
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(associatedAppInfo);
+        Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
+                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
+        Mockito.verify(mPackageManager).setApplicationEnabledSetting(
+                CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager).setApplicationEnabledSetting(
+                ASSOCIATED_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                PackageManager.DONT_KILL_APP, USER_ID, CALLING_PACKAGE);
         Mockito.verify(mPackageManager).grantDefaultPermissionsToEnabledCarrierApps(
                 new String[] {appInfo.packageName}, USER_ID);
     }
@@ -220,11 +341,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -242,9 +363,10 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, USER_ID, CARRIER_APPS);
+                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
+                ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -261,11 +383,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -282,9 +404,10 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, USER_ID, CARRIER_APPS);
+                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
+                ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -301,11 +424,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -322,9 +445,10 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, USER_ID, CARRIER_APPS);
+                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
+                ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -341,11 +465,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -362,9 +486,10 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, USER_ID, CARRIER_APPS);
+                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
+                ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -373,22 +498,108 @@
                         Mockito.any(String[].class), Mockito.anyInt());
     }
 
-    /** Configured app has no privileges, and is in the default state - should disable until use. */
+    /**
+     * Configured app has no privileges, and is in the default state - should disable until use.
+     * Associated app is enabled and should not be touched.
+     */
     @Test @SmallTest
-    public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Default() throws Exception {
+    public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_EnabledAssociated_Default()
+            throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+        ApplicationInfo associatedAppInfo = new ApplicationInfo();
+        associatedAppInfo.packageName = ASSOCIATED_APP;
+        associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager).setApplicationEnabledSetting(
                 CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0, USER_ID,
                 CALLING_PACKAGE);
+        Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
+                ASSOCIATED_APP, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
+                USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager, Mockito.never())
+                .grantDefaultPermissionsToEnabledCarrierApps(
+                        Mockito.any(String[].class), Mockito.anyInt());
+    }
+
+    /**
+     * Configured app has no privileges, and is in the default state along with associated app -
+     * should disable both.
+     */
+    @Test @SmallTest
+    public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Associated_Default()
+            throws Exception {
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
+        appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+        ApplicationInfo associatedAppInfo = new ApplicationInfo();
+        associatedAppInfo.packageName = ASSOCIATED_APP;
+        associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(associatedAppInfo);
+        Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
+                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+        CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
+        Mockito.verify(mPackageManager).setApplicationEnabledSetting(
+                CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0, USER_ID,
+                CALLING_PACKAGE);
+        Mockito.verify(mPackageManager).setApplicationEnabledSetting(
+                ASSOCIATED_APP, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
+                USER_ID, CALLING_PACKAGE);
+        Mockito.verify(mPackageManager, Mockito.never())
+                .grantDefaultPermissionsToEnabledCarrierApps(
+                        Mockito.any(String[].class), Mockito.anyInt());
+    }
+
+    /**
+     * Configured app has no privileges, and is in the default state along with associated app, and
+     * disabling has already occurred - should only disable configured app.
+     */
+    @Test @SmallTest
+    public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Associated_Default_AlreadyRun()
+            throws Exception {
+        Settings.Secure.putIntForUser(
+                mContentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1, USER_ID);
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
+        appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+        ApplicationInfo associatedAppInfo = new ApplicationInfo();
+        associatedAppInfo.packageName = ASSOCIATED_APP;
+        associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID))
+                .thenReturn(associatedAppInfo);
+        Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
+                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+        CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
+        Mockito.verify(mPackageManager).setApplicationEnabledSetting(
+                CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0, USER_ID,
+                CALLING_PACKAGE);
+        Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
+                Mockito.eq(ASSOCIATED_APP), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
+                Mockito.anyString());
         Mockito.verify(mPackageManager, Mockito.never())
                 .grantDefaultPermissionsToEnabledCarrierApps(
                         Mockito.any(String[].class), Mockito.anyInt());
@@ -402,9 +613,10 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, USER_ID, CARRIER_APPS);
+                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
+                ASSOCIATED_APPS);
         Mockito.verify(mPackageManager).setApplicationEnabledSetting(
                 CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0, USER_ID,
                 CALLING_PACKAGE);
@@ -422,11 +634,11 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                mTelephonyManager, USER_ID, CARRIER_APPS);
+                mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -444,9 +656,10 @@
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
-                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, USER_ID, CARRIER_APPS);
+                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
+                ASSOCIATED_APPS);
         Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
                 Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
                 Mockito.anyString());
@@ -454,5 +667,21 @@
                 .grantDefaultPermissionsToEnabledCarrierApps(
                         Mockito.any(String[].class), Mockito.anyInt());
     }
+
+    class SettingsMockContentProvider extends MockContentProvider {
+        private int mExpectedValue;
+
+        @Override
+        public Bundle call(String method, String request, Bundle args) {
+            Bundle result = new Bundle();
+            if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
+                result.putString(Settings.NameValueTable.VALUE, Integer.toString(mExpectedValue));
+            } else {
+                mExpectedValue = Integer.parseInt(args.getString(Settings.NameValueTable.VALUE));
+            }
+            return result;
+        }
+    }
+
 }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
index fb4ab24..edb4554 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
@@ -353,21 +353,34 @@
         // verify getCurrentCalls is called on init
         verify(mSimulatedCommandsVerifier).getCurrentCalls(any(Message.class));
 
-        // update phone type
-        mCTUT.updatePhoneType();
+        // update phone type (call the function on same thread as the call tracker)
+        Handler updatePhoneTypeHandler = new Handler(mCTUT.getLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                mCTUT.updatePhoneType();
+            }
+        };
+        updatePhoneTypeHandler.sendEmptyMessage(0);
+        waitForMs(100);
 
         // verify getCurrentCalls is called on updating phone type
         verify(mSimulatedCommandsVerifier, times(2)).getCurrentCalls(any(Message.class));
 
-        // verify that if phone type is updated, calls and callTracker go to idle
+        // we'd like to verify that if phone type is updated, calls and callTracker go to idle.
+        // However, as soon as phone type is updated, call tracker queries for calls from RIL and
+        // will go back to OFFHOOK
+
+        // call tracker goes to OFFHOOK
         testMOCallPickUp();
 
-        // update phone type
-        mCTUT.updatePhoneType();
+        // update phone type - call tracker goes to IDLE and then due to getCurrentCalls(),
+        // goes back to OFFHOOK
+        updatePhoneTypeHandler.sendEmptyMessage(0);
+        waitForMs(100);
 
         // verify CT and calls go to idle
-        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
-        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
+        assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState());
+        assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState());
         assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState());
         assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mRingingCall.getState());
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
index 8346a9d..7030440 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
@@ -63,6 +63,13 @@
     }
 
     @SmallTest
+    public void testLang_India() throws Exception {
+        assertEquals(MccTable.defaultLanguageForMcc(404), "en");
+        assertEquals(MccTable.defaultLanguageForMcc(405), "en");
+        assertEquals(MccTable.defaultLanguageForMcc(406), "en");
+    }
+
+    @SmallTest
     public void testSmDigits() throws Exception {
         assertEquals(MccTable.smallestDigitsMccForMnc(312), 3);
         assertEquals(MccTable.smallestDigitsMccForMnc(430), 2);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 101640e..805ee93 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -58,6 +58,7 @@
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriManager;
 import com.android.internal.telephony.dataconnection.DcTracker;
+import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.mocks.TelephonyRegistryMock;
@@ -172,6 +173,8 @@
     protected IBinder mConnMetLoggerBinder;
     @Mock
     protected CarrierSignalAgent mCarrierSignalAgent;
+    @Mock
+    protected ImsExternalCallTracker mImsExternalCallTracker;
 
     protected TelephonyManager mTelephonyManager;
     protected SubscriptionManager mSubscriptionManager;
@@ -340,6 +343,8 @@
                         anyInt(), any(Object.class));
         doReturn(mIDeviceIdleController).when(mTelephonyComponentFactory)
                 .getIDeviceIdleController();
+        doReturn(mImsExternalCallTracker).when(mTelephonyComponentFactory).
+                makeImsExternalCallTracker(any(ImsPhone.class));
 
         //mPhone
         doReturn(mContext).when(mPhone).getContext();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsParserTest.java b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsParserTest.java
index 6caea7d..12a4655 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsParserTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsParserTest.java
@@ -16,9 +16,7 @@
 package com.android.internal.telephony;
 
 import android.test.suitebuilder.annotation.SmallTest;
-
 import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData;
-
 import junit.framework.TestCase;
 
 public class VisualVoicemailSmsParserTest extends TestCase {
@@ -147,4 +145,42 @@
         assertEquals("STATUS", result.prefix);
         assertEquals("", result.fields.getString("key"));
     }
+
+    @SmallTest
+    public void testAlternativeParsing_Mboxupdate() {
+        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
+            "MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=bar");
+
+        assertEquals("MBOXUPDATE", result.prefix);
+        assertEquals("1", result.fields.getString("m"));
+        assertEquals("example.com", result.fields.getString("server"));
+        assertEquals("143", result.fields.getString("port"));
+        assertEquals("foo@example.com", result.fields.getString("name"));
+        assertEquals("bar", result.fields.getString("pw"));
+    }
+
+    @SmallTest
+    public void testAlternativeParsing_Unrecognized() {
+        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
+            "UNRECOGNIZED?cmd=STATUS");
+
+        assertEquals("UNRECOGNIZED", result.prefix);
+        assertEquals("STATUS", result.fields.getString("cmd"));
+    }
+
+    @SmallTest
+    public void testAlternativeParsingFail_MissingSeparator() {
+        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
+            "I send SMS in weird formats");
+
+        assertNull(result);
+    }
+
+    @SmallTest
+    public void testAlternativeParsingFail_NotWhitelistedEvent() {
+        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
+            "AreYouStillThere?");
+
+        assertNull(result);
+    }
 }