Merge "fix the class not found crash"
diff --git a/jarjar-rules-shared.txt b/jarjar-rules-shared.txt
index f49538e..45be9f5 100644
--- a/jarjar-rules-shared.txt
+++ b/jarjar-rules-shared.txt
@@ -2,13 +2,13 @@
 rule android.os.Registrant* com.android.internal.telephony.Registrant@1
 rule android.hidl.** android.internal.hidl.@1
 rule android.util.LocalLog* com.android.internal.telephony.LocalLog@1
-rule android.util.Slog* com.android.internal.telephony.Slog@1
 rule android.util.TimeUtils* com.android.internal.telephony.TimeUtils@1
-rule com.android.internal.util.Preconditions* com.android.internal.telephony.Preconditions@1
 rule com.android.internal.os.SomeArgs* com.android.internal.telephony.SomeArgs@1
-rule com.android.internal.util.DumpUtils* com.android.internal.telephony.DumpUtils@1
-rule com.android.internal.util.XmlUtils* com.android.internal.telephony.XmlUtils@1
+rule com.android.internal.util.ArrayUtils* com.android.internal.telephony.ArrayUtils@1
+rule com.android.internal.util.FastXmlSerializer* com.android.internal.telephony.FastXmlSerializer@1
 rule com.android.internal.util.HexDump* com.android.internal.telephony.HexDump@1
+rule com.android.internal.util.IndentingPrintWriter* com.android.internal.telephony.IndentingPrintWriter@1
+rule com.android.internal.util.Preconditions* com.android.internal.telephony.Preconditions@1
 rule com.android.internal.util.State* com.android.internal.telephony.State@1
 rule com.android.internal.util.StateMachine* com.android.internal.telephony.StateMachine@1
-rule com.android.internal.util.IndentingPrintWriter* com.android.internal.telephony.IndentingPrintWriter@1
\ No newline at end of file
+rule com.android.internal.util.UserIcons* com.android.internal.telephony.UserIcons@1
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index ec2acf4..a2fc621 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -262,6 +262,46 @@
     ROAMING_TYPE_INTERNATIONAL = 3;
   }
 
+  // Frequency range
+  enum FrequencyRange {
+    // Unknown. The default value.
+    FREQUENCY_RANGE_UNKNOWN = 0;
+
+    // Frequency range is below 1GHz.
+    FREQUENCY_RANGE_LOW = 1;
+
+    // Frequency range is between 1GHz and 3GHz.
+    FREQUENCY_RANGE_MID = 2;
+
+    // Frequency range is between 3GHz and 6GHz.
+    FREQUENCY_RANGE_HIGH = 3;
+
+    // Frequency range is above 6GHz (millimeter wave frequency).
+    FREQUENCY_RANGE_MMWAVE = 4;
+  }
+
+  // NR (5G) state
+  enum NrState {
+    // The device isn't camped on an LTE cell
+    // or the LTE cell doesn't support EN-DC.
+    NR_STATE_NONE = 0;
+
+    // The device is camped on an LTE cell that supports EN-DC
+    // but either DCNR is restricted
+    // or NR is not supported by the selected PLMN.
+    NR_STATE_RESTRICTED = 1;
+
+    // The device is camped on an LTE cell that supports EN-DC
+    // and both DCNR is not restricted and NR is supported
+    // by the selected PLMN.
+    NR_STATE_NOT_RESTRICTED = 2;
+
+    // The device is camped on an LTE cell that supports EN-DC
+    // and connected to at least one 5G cell
+    // as a secondary serving cell.
+    NR_STATE_CONNECTED = 3;
+  }
+
   // Current registered operator
   optional TelephonyOperator voice_operator = 1;
 
@@ -282,6 +322,12 @@
 
   // Current Channel Number
   optional int32 channel_number = 7;
+
+  // Current NR frequency range
+  optional FrequencyRange nr_frequency_range = 8;
+
+  // Current NR state
+  optional NrState nr_state = 9;
 }
 
 // Radio access families
@@ -749,6 +795,9 @@
 
     // Emergency Number update event (Device HAL >= 1.4).
     EMERGENCY_NUMBER_REPORT = 21;
+
+    // Network capabilities change event.
+    NETWORK_CAPABILITIES_CHANGED = 22;
   }
 
   enum ApnType {
@@ -1651,6 +1700,11 @@
     optional string preferApn = 12;
   }
 
+  message NetworkCapabilitiesInfo {
+    // Is network unmetered
+    optional bool is_network_unmetered = 1;
+  }
+
   // Time when event happened on device, in milliseconds since epoch
   optional int64 timestamp_millis = 1;
 
@@ -1723,6 +1777,9 @@
 
   // Updated Emergency Call info.
   optional EmergencyNumberInfo updated_emergency_number = 25;
+
+  // NetworkCapabilities changed info.
+  optional NetworkCapabilitiesInfo network_capabilities = 26;
 }
 
 message ActiveSubscriptionInfo {
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index 7004ef2..f0a718a 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -101,6 +101,7 @@
     protected RegistrantList mPhysicalChannelConfigurationRegistrants = new RegistrantList();
     protected RegistrantList mLceInfoRegistrants = new RegistrantList();
     protected RegistrantList mEmergencyNumberListRegistrants = new RegistrantList();
+    protected RegistrantList mUiccApplicationsEnablementRegistrants = new RegistrantList();
 
     @UnsupportedAppUsage
     protected Registrant mGsmSmsRegistrant;
@@ -952,7 +953,7 @@
 
     @Override
     public void registerForModemReset(Handler h, int what, Object obj) {
-        mModemResetRegistrants.add(new Registrant(h, what, obj));
+        mModemResetRegistrants.addUnique(h, what, obj);
     }
 
     @Override
@@ -962,7 +963,7 @@
 
     @Override
     public void registerForPcoData(Handler h, int what, Object obj) {
-        mPcoDataRegistrants.add(new Registrant(h, what, obj));
+        mPcoDataRegistrants.addUnique(h, what, obj);
     }
 
     @Override
@@ -972,7 +973,7 @@
 
     @Override
     public void registerForCarrierInfoForImsiEncryption(Handler h, int what, Object obj) {
-        mCarrierInfoForImsiEncryptionRegistrants.add(new Registrant(h, what, obj));
+        mCarrierInfoForImsiEncryptionRegistrants.addUnique(h, what, obj);
     }
 
     @Override
@@ -993,4 +994,26 @@
             mNattKeepaliveStatusRegistrants.remove(h);
         }
     }
+
+    /**
+     * Registers the handler for RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED events.
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    @Override
+    public void registerUiccApplicationEnablementChanged(Handler h, int what, Object obj) {
+        mUiccApplicationsEnablementRegistrants.addUnique(h, what, obj);
+    }
+
+    /**
+     * Unregisters the handler for RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED events.
+     *
+     * @param h Handler for notification message.
+     */
+    @Override
+    public void unregisterUiccApplicationEnablementChanged(Handler h) {
+        mUiccApplicationsEnablementRegistrants.remove(h);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java b/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java
index 67e07bc..ea6a6ec 100644
--- a/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java
@@ -17,12 +17,11 @@
 
 package com.android.internal.telephony;
 
-import android.app.ActivityThread;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothMapClient;
 import android.bluetooth.BluetoothProfile;
+import android.content.Context;
 import android.net.Uri;
 import android.telecom.PhoneAccount;
 import android.telephony.SmsManager;
@@ -40,7 +39,7 @@
     /**
      * Sends text through connected Bluetooth device
      */
-    public void sendText(String destAddr, String text, PendingIntent sentIntent,
+    public void sendText(Context context, String destAddr, String text, PendingIntent sentIntent,
             PendingIntent deliveryIntent, SubscriptionInfo info) {
         BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
         if (btAdapter == null) {
@@ -54,7 +53,7 @@
             sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS);
             return;
         }
-        btAdapter.getProfileProxy(ActivityThread.currentApplication().getApplicationContext(),
+        btAdapter.getProfileProxy(context.getApplicationContext(),
                 new MapMessageSender(destAddr, text, device, sentIntent, deliveryIntent),
                 BluetoothProfile.MAP_CLIENT);
     }
@@ -99,14 +98,19 @@
             if (profile != BluetoothProfile.MAP_CLIENT) {
                 return;
             }
-            BluetoothMapClient mapProfile = (BluetoothMapClient) proxy;
+            // Comment out the method for mainline (b/143848423). The profile is not for a phone,
+            // so it will not be enabled.
+/*            BluetoothMapClient mapProfile = (BluetoothMapClient) proxy;
             if (mMessage != null) {
                 Log.d(LOG_TAG, "Sending message thru bluetooth");
                 mapProfile.sendMessage(mDevice, mDestAddr, mMessage, mSentIntent, mDeliveryIntent);
                 mMessage = null;
             }
             BluetoothAdapter.getDefaultAdapter()
-                    .closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile);
+                    .closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile);*/
+            if (mMessage != null) {
+                throw new RuntimeException("Can't send message through BluetoothMapClient");
+            }
         }
 
         @Override
diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
index ad753db..e9c3a73 100644
--- a/src/java/com/android/internal/telephony/CarrierSignalAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
@@ -36,7 +36,7 @@
 import android.util.LocalLog;
 import android.util.Log;
 
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
diff --git a/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java b/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
index 132ea3b..09465ee 100644
--- a/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
+++ b/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
@@ -60,7 +60,7 @@
     private static final int EVENT_NEW_GSM_SMS_CB = 0;
     private static final int EVENT_NEW_CDMA_SMS_CB = 1;
     private static final int EVENT_NEW_CDMA_SCP_MESSAGE = 2;
-    private boolean mEnabled;
+    private boolean mEnabled = false;
 
     public CellBroadcastServiceManager(Context context, Phone phone) {
         Log.d(TAG, "CellBroadcastServiceManager created for phone " + phone.getPhoneId());
@@ -111,6 +111,9 @@
      * Disable the CB module. The manager's handler will no longer receive CB messages from the RIL.
      */
     public void disable() {
+        if (mEnabled == false) {
+            return;
+        }
         mEnabled = false;
         mPhone.mCi.unSetOnNewGsmBroadcastSms(mModuleCellBroadcastHandler);
         if (sServiceConnection.mService != null) {
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 273de72..c67c675 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -656,6 +656,22 @@
      void unregisterForRilConnected(Handler h);
 
     /**
+     * Registers the handler for RIL_UNSOL_SIM_DETACH_FROM_NETWORK_CONFIG_CHANGED events.
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    default void registerUiccApplicationEnablementChanged(Handler h, int what, Object obj) {};
+
+    /**
+     * Unregisters the handler for RIL_UNSOL_SIM_DETACH_FROM_NETWORK_CONFIG_CHANGED events.
+     *
+     * @param h Handler for notification message.
+     */
+    default void unregisterUiccApplicationEnablementChanged(Handler h) {};
+
+    /**
      * Supply the ICC PIN to the ICC card
      *
      *  returned message
@@ -2393,6 +2409,28 @@
      */
     default void getModemStatus(Message result) {};
 
+    /**
+     * Enable or disable uicc applications on the SIM.
+     *
+     * @param enable enable or disable UiccApplications on the SIM.
+     * @param onCompleteMessage a Message to return to the requester
+     */
+    default void enableUiccApplications(boolean enable, Message onCompleteMessage) {}
+
+    /**
+     * Whether uicc applications are enabled or not.
+     *
+     * @param onCompleteMessage a Message to return to the requester
+     */
+    default void areUiccApplicationsEnabled(Message onCompleteMessage) {}
+
+    /**
+     * Whether {@link #enableUiccApplications} is supported, based on IRadio version.
+     */
+    default boolean canToggleUiccApplicationsEnablement() {
+        return false;
+    }
+
     default List<ClientRequestStats> getClientRequestStats() {
         return null;
     }
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 41e0053..8405e5f 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -88,6 +88,7 @@
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
+import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.IccException;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
@@ -100,7 +101,7 @@
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UiccProfile;
 import com.android.internal.telephony.uicc.UiccSlot;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -152,6 +153,7 @@
     private String mMeid;
     // string to define how the carrier specifies its own ota sp number
     private String mCarrierOtaSpNumSchema;
+    private boolean mUiccApplicationsEnabled = true;
 
     // A runnable which is used to automatically exit from Ecm after a period of time.
     private Runnable mExitEcmRunnable = new Runnable() {
@@ -324,6 +326,8 @@
         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCi.registerForOn(this, EVENT_RADIO_ON, null);
         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
+        mCi.registerUiccApplicationEnablementChanged(this, EVENT_UICC_APPS_ENABLEMENT_CHANGED,
+                null);
         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
 
         //GSM
@@ -2404,6 +2408,8 @@
 
         mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
         mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
+        mCi.areUiccApplicationsEnabled(obtainMessage(EVENT_GET_UICC_APPS_ENABLEMENT_DONE));
+
         startLceAfterRadioIsAvailable();
     }
 
@@ -2843,6 +2849,18 @@
                     onComplete.sendToTarget();
                 }
                 break;
+            case EVENT_GET_UICC_APPS_ENABLEMENT_DONE:
+            case EVENT_UICC_APPS_ENABLEMENT_CHANGED: {
+                ar = (AsyncResult) msg.obj;
+                if (ar == null) return;
+                if (ar.exception != null) {
+                    logd("Received exception on event" + msg.what + " : " + ar.exception);
+                    return;
+                }
+
+                mUiccApplicationsEnabled = (boolean) ar.result;
+                break;
+            }
             default:
                 super.handleMessage(msg);
         }
@@ -4036,4 +4054,30 @@
                 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF);
         updateUiTtyMode(ttyMode);
     }
+
+    // Enable or disable uicc applications.
+    @Override
+    public void enableUiccApplications(boolean enable, Message onCompleteMessage) {
+        // First check if card is present. Otherwise mUiccApplicationsDisabled doesn't make
+        // any sense.
+        UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId);
+        if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT) {
+            if (onCompleteMessage != null) {
+                AsyncResult.forMessage(onCompleteMessage, null,
+                        new IllegalStateException("No SIM card is present"));
+                onCompleteMessage.sendToTarget();
+            }
+            return;
+        }
+
+        mCi.enableUiccApplications(enable, onCompleteMessage);
+    }
+
+    /**
+     * Whether disabling a physical subscription is supported or not.
+     */
+    @Override
+    public boolean canDisablePhysicalSubscription() {
+        return mCi.canToggleUiccApplicationsEnablement();
+    }
 }
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index d2f256a..66a86e6 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -24,8 +24,11 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
@@ -36,9 +39,11 @@
 import android.os.Message;
 import android.os.UserManager;
 import android.provider.Telephony;
+import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
+import android.telephony.SubscriptionManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.util.LocalLog;
 import android.util.Log;
@@ -181,6 +186,21 @@
         mAppOps = appOps;
         mDispatchersController = dispatchersController;
         mSmsPermissions = new SmsPermissions(phone, context, appOps);
+
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED
+                                .equals(intent.getAction())) {
+                            if (mPhone.getPhoneId() == intent.getIntExtra(
+                                    CarrierConfigManager.EXTRA_SLOT_INDEX,
+                                    SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
+                                mCellBroadcastRangeManager.updateRanges();
+                            }
+                        }
+                    }
+                }, new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
     }
 
     protected void markMessagesAsRead(ArrayList<byte[]> messages) {
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index 934eddf..808c1b7 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -237,7 +237,7 @@
     @UnsupportedAppUsage
     IDeviceIdleController mDeviceIdleController;
 
-    protected static boolean sEnableCbModule = false;
+    protected static boolean sEnableCbModule = true;
 
     protected CellBroadcastServiceManager mCellBroadcastServiceManager;
 
@@ -1166,7 +1166,7 @@
                 UserHandle targetUser = UserHandle.of(users[i]);
                 if (users[i] != UserHandle.USER_SYSTEM) {
                     // Is the user not allowed to use SMS?
-                    if (mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) {
+                    if (hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) {
                         continue;
                     }
                     // Skip unknown users and managed profiles as well
@@ -1195,6 +1195,12 @@
         }
     }
 
+    private boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
+        final List<UserManager.EnforcingUser> sources = mUserManager
+                .getUserRestrictionSources(restrictionKey, userHandle);
+        return (sources != null && !sources.isEmpty());
+    }
+
     /**
      * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table.
      */
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index 4b8a043..40e94eb 100755
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -58,7 +58,6 @@
  */
 public class LocaleTracker extends Handler {
     private static final boolean DBG = true;
-    private static final String TAG = LocaleTracker.class.getSimpleName();
 
     /** Event for getting cell info from the modem */
     private static final int EVENT_REQUEST_CELL_INFO = 1;
@@ -125,6 +124,8 @@
     /** The maximum fail count to prevent delay time overflow */
     private static final int MAX_FAIL_COUNT = 30;
 
+    private String mTag;
+
     private final Phone mPhone;
 
     private final NitzStateMachine mNitzStateMachine;
@@ -241,6 +242,7 @@
         mPhone = phone;
         mNitzStateMachine = nitzStateMachine;
         mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
+        mTag = LocaleTracker.class.getSimpleName() + "-" + mPhone.getPhoneId();
 
         final IntentFilter filter = new IntentFilter();
         filter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
@@ -611,11 +613,11 @@
     }
 
     private void log(String msg) {
-        Rlog.d(TAG, msg);
+        Rlog.d(mTag, msg);
     }
 
     private void loge(String msg) {
-        Rlog.e(TAG, msg);
+        Rlog.e(mTag, msg);
     }
 
     /**
@@ -627,7 +629,7 @@
      */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-        pw.println("LocaleTracker:");
+        pw.println("LocaleTracker-" + mPhone.getPhoneId() + ":");
         ipw.increaseIndent();
         ipw.println("mIsTracking = " + mIsTracking);
         ipw.println("mOperatorNumeric = " + mOperatorNumeric);
diff --git a/src/java/com/android/internal/telephony/MccTable.java b/src/java/com/android/internal/telephony/MccTable.java
index d4c2e9a..1016cbe 100644
--- a/src/java/com/android/internal/telephony/MccTable.java
+++ b/src/java/com/android/internal/telephony/MccTable.java
@@ -26,8 +26,8 @@
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.telephony.Rlog;
 import android.text.TextUtils;
-import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -260,7 +260,7 @@
     public static String defaultLanguageForMcc(int mcc) {
         MccEntry entry = entryForMcc(mcc);
         if (entry == null) {
-            Slog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): no country for mcc");
+            Rlog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): no country for mcc");
             return null;
         }
 
@@ -274,8 +274,8 @@
         // Ask CLDR for the language this country uses...
         ULocale likelyLocale = ULocale.addLikelySubtags(new ULocale("und", country));
         String likelyLanguage = likelyLocale.getLanguage();
-        Slog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): country " + country + " uses " +
-               likelyLanguage);
+        Rlog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): country " + country + " uses "
+                + likelyLanguage);
         return likelyLanguage;
     }
 
@@ -306,13 +306,13 @@
      * @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end
      */
     public static void updateMccMncConfiguration(Context context, String mccmnc) {
-        Slog.d(LOG_TAG, "updateMccMncConfiguration mccmnc='" + mccmnc);
+        Rlog.d(LOG_TAG, "updateMccMncConfiguration mccmnc='" + mccmnc);
 
         if (Build.IS_DEBUGGABLE) {
             String overrideMcc = SystemProperties.get("persist.sys.override_mcc");
             if (!TextUtils.isEmpty(overrideMcc)) {
                 mccmnc = overrideMcc;
-                Slog.d(LOG_TAG, "updateMccMncConfiguration overriding mccmnc='" + mccmnc + "'");
+                Rlog.d(LOG_TAG, "updateMccMncConfiguration overriding mccmnc='" + mccmnc + "'");
             }
         }
 
@@ -323,11 +323,11 @@
                 mcc = Integer.parseInt(mccmnc.substring(0, 3));
                 mnc = Integer.parseInt(mccmnc.substring(3));
             } catch (NumberFormatException | StringIndexOutOfBoundsException ex) {
-                Slog.e(LOG_TAG, "Error parsing IMSI: " + mccmnc + ". ex=" + ex);
+                Rlog.e(LOG_TAG, "Error parsing IMSI: " + mccmnc + ". ex=" + ex);
                 return;
             }
 
-            Slog.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc);
+            Rlog.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc);
 
             try {
                 Configuration config = new Configuration();
@@ -339,13 +339,13 @@
                 }
 
                 if (updateConfig) {
-                    Slog.d(LOG_TAG, "updateMccMncConfiguration updateConfig config=" + config);
+                    Rlog.d(LOG_TAG, "updateMccMncConfiguration updateConfig config=" + config);
                     ActivityManager.getService().updateConfiguration(config);
                 } else {
-                    Slog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");
+                    Rlog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");
                 }
             } catch (RemoteException e) {
-                Slog.e(LOG_TAG, "Can't update configuration", e);
+                Rlog.e(LOG_TAG, "Can't update configuration", e);
             }
         }
     }
@@ -400,7 +400,7 @@
     private static Locale getLocaleForLanguageCountry(Context context, String language,
             String country) {
         if (language == null) {
-            Slog.d(LOG_TAG, "getLocaleForLanguageCountry: skipping no language");
+            Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: skipping no language");
             return null; // no match possible
         }
         if (country == null) {
@@ -428,8 +428,8 @@
                 if (l.getLanguage().equals(target.getLanguage())) {
                     // If we got a perfect match, we're done.
                     if (l.getCountry().equals(target.getCountry())) {
-                        Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got perfect match: " +
-                               l.toLanguageTag());
+                        Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: got perfect match: "
+                                + l.toLanguageTag());
                         return l;
                     }
 
@@ -439,13 +439,13 @@
             }
 
             if (languageMatches.isEmpty()) {
-                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " + language);
+                Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " + language);
                 return null;
             }
 
             Locale bestMatch = lookupFallback(target, languageMatches);
             if (bestMatch != null) {
-                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got a fallback match: "
+                Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: got a fallback match: "
                         + bestMatch.toLanguageTag());
                 return bestMatch;
             } else {
@@ -459,7 +459,7 @@
                     LocaleStore.fillCache(context);
                     LocaleInfo targetInfo = LocaleStore.getLocaleInfo(target);
                     if (targetInfo.isTranslated()) {
-                        Slog.d(LOG_TAG, "getLocaleForLanguageCountry: "
+                        Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: "
                                 + "target locale is translated: " + target);
                         return target;
                     }
@@ -469,12 +469,12 @@
                 // unless we get a perfect match later. Note that these come back in no
                 // particular order, so there's no reason to think the first match is
                 // a particularly good match.
-                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got language-only match: "
+                Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: got language-only match: "
                         + language);
                 return languageMatches.get(0);
             }
         } catch (Exception e) {
-            Slog.d(LOG_TAG, "getLocaleForLanguageCountry: exception", e);
+            Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: exception", e);
         }
 
         return null;
@@ -494,14 +494,14 @@
         String language = hasSimLanguage ? simLanguage : MccTable.defaultLanguageForMcc(mcc);
         String country = MccTable.countryCodeForMcc(mcc);
 
-        Slog.d(LOG_TAG, "getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
+        Rlog.d(LOG_TAG, "getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
         final Locale locale = getLocaleForLanguageCountry(context, language, country);
 
         // If we couldn't find a locale that matches the SIM language, give it a go again
         // with the "likely" language for the given country.
         if (locale == null && hasSimLanguage) {
             language = MccTable.defaultLanguageForMcc(mcc);
-            Slog.d(LOG_TAG, "[retry ] getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
+            Rlog.d(LOG_TAG, "[retry ] getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
             return getLocaleForLanguageCountry(context, language, country);
         }
 
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index 1ce360f..3610be8 100644
--- a/src/java/com/android/internal/telephony/MultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java
@@ -51,7 +51,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index db76e84..8184305 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -195,7 +195,9 @@
     protected static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = 50;
     protected static final int EVENT_GET_AVAILABLE_NETWORKS_DONE    = 51;
 
-    private static final int EVENT_ALL_DATA_DISCONNECTED         = 52;
+    private static final int EVENT_ALL_DATA_DISCONNECTED            = 52;
+    protected static final int EVENT_UICC_APPS_ENABLEMENT_CHANGED   = 53;
+    protected static final int EVENT_GET_UICC_APPS_ENABLEMENT_DONE  = 54;
 
     protected static final int EVENT_LAST = EVENT_ALL_DATA_DISCONNECTED;
 
@@ -2585,7 +2587,8 @@
             options.setBackgroundActivityStartsAllowed(true);
             Intent intent = new Intent(TelephonyIntents.SECRET_CODE_ACTION,
                     Uri.parse("android_secret_code://" + code));
-            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+            intent.addFlags(
+                    Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND);
             mContext.sendBroadcast(intent, null, options.toBundle());
 
             // {@link TelephonyManager.ACTION_SECRET_CODE} will replace {@link
@@ -2593,7 +2596,8 @@
             // that both of these two actions will be broadcast.
             Intent secrectCodeIntent = new Intent(TelephonyManager.ACTION_SECRET_CODE,
                     Uri.parse("android_secret_code://" + code));
-            secrectCodeIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+            secrectCodeIntent.addFlags(
+                    Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND);
             mContext.sendBroadcast(secrectCodeIntent, null, options.toBundle());
         }
     }
@@ -4074,6 +4078,20 @@
     }
 
     /**
+     * Enable or disable uicc applications.
+     * @param enable whether to enable or disable uicc applications.
+     * @param onCompleteMessage callback for async operation. Ignored if blockingCall is true.
+     */
+    public void enableUiccApplications(boolean enable, Message onCompleteMessage) {}
+
+    /**
+     * Whether disabling a physical subscription is supported or not.
+     */
+    public boolean canDisablePhysicalSubscription() {
+        return false;
+    }
+
+    /**
      * Get the HAL version.
      *
      * @return the current HalVersion
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index a0be155..695e1e7 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -1484,6 +1484,43 @@
     }
 
     /**
+     * Convert to DataProfileInfo defined in radio/1.5/types.hal
+     * @param dp Data profile
+     * @return A converted data profile
+     */
+    private static android.hardware.radio.V1_5.DataProfileInfo convertToHalDataProfile15(
+            DataProfile dp) {
+        android.hardware.radio.V1_5.DataProfileInfo dpi =
+                new android.hardware.radio.V1_5.DataProfileInfo();
+
+        dpi.base.apn = dp.getApn();
+        dpi.base.protocol = dp.getProtocolType();
+        dpi.base.roamingProtocol = dp.getRoamingProtocolType();
+        dpi.base.authType = dp.getAuthType();
+        dpi.base.user = dp.getUserName();
+        dpi.base.password = dp.getPassword();
+        dpi.base.type = dp.getType();
+        dpi.base.maxConnsTime = dp.getMaxConnectionsTime();
+        dpi.base.maxConns = dp.getMaxConnections();
+        dpi.base.waitTime = dp.getWaitTime();
+        dpi.base.enabled = dp.isEnabled();
+        dpi.supportedApnTypesBitmap = dp.getSupportedApnTypesBitmask();
+        // Shift by 1 bit due to the discrepancy between
+        // android.hardware.radio.V1_0.RadioAccessFamily and the bitmask version of
+        // ServiceState.RIL_RADIO_TECHNOLOGY_XXXX.
+        dpi.base.bearerBitmap = ServiceState.convertNetworkTypeBitmaskToBearerBitmask(
+            dp.getBearerBitmask()) << 1;
+        dpi.base.mtu = dp.getMtu();
+        dpi.base.persistent = dp.isPersistent();
+        dpi.base.preferred = dp.isPreferred();
+
+        // profile id is only meaningful when it's persistent on the modem.
+        dpi.base.profileId = (dpi.base.persistent) ? dp.getProfileId() : DataProfileId.INVALID;
+
+        return dpi;
+    }
+
+    /**
      * Convert NV reset type into ResetNvType defined in types.hal.
      * @param resetType NV reset type.
      * @return Converted reset type in integer or -1 if param is invalid.
@@ -1527,7 +1564,26 @@
             }
 
             try {
-                if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
+                if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
+                    // IRadio V1.5
+                    android.hardware.radio.V1_5.IRadio radioProxy15 =
+                            (android.hardware.radio.V1_5.IRadio) radioProxy;
+
+                    // Convert to HAL data profile
+                    android.hardware.radio.V1_5.DataProfileInfo dpi =
+                            convertToHalDataProfile15(dataProfile);
+
+                    if (RILJ_LOGD) {
+                        riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                                + ",accessNetworkType="
+                                + AccessNetworkType.toString(accessNetworkType) + ",isRoaming="
+                                + isRoaming + ",allowRoaming=" + allowRoaming + "," + dataProfile
+                                + ",addresses=" + addresses + ",dnses=" + dnses);
+                    }
+
+                    radioProxy15.setupDataCall_1_5(rr.mSerial, accessNetworkType, dpi, allowRoaming,
+                            reason, addresses, dnses);
+                } else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
                     // IRadio V1.4
                     android.hardware.radio.V1_4.IRadio radioProxy14 =
                             (android.hardware.radio.V1_4.IRadio) radioProxy;
@@ -3597,7 +3653,13 @@
             }
 
             try {
-                if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
+                if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
+                    // v1.5
+                    android.hardware.radio.V1_5.IRadio radioProxy15 =
+                            (android.hardware.radio.V1_5.IRadio) radioProxy;
+                    radioProxy15.setInitialAttachApn_1_5(rr.mSerial,
+                            convertToHalDataProfile15(dataProfile));
+                } else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
                     // v1.4
                     android.hardware.radio.V1_4.IRadio radioProxy14 =
                             (android.hardware.radio.V1_4.IRadio) radioProxy;
@@ -4000,7 +4062,29 @@
 
             RILRequest rr = null;
             try {
-                if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
+                if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
+                    // V1.5
+                    android.hardware.radio.V1_5.IRadio radioProxy15 =
+                            (android.hardware.radio.V1_5.IRadio) radioProxy;
+
+                    rr = obtainRequest(RIL_REQUEST_SET_DATA_PROFILE, result,
+                            mRILDefaultWorkSource);
+
+                    ArrayList<android.hardware.radio.V1_5.DataProfileInfo> dpis = new ArrayList<>();
+                    for (DataProfile dp : dps) {
+                        dpis.add(convertToHalDataProfile15(dp));
+                    }
+
+                    if (RILJ_LOGD) {
+                        riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                                + " with data profiles : ");
+                        for (DataProfile profile : dps) {
+                            riljLog(profile.toString());
+                        }
+                    }
+
+                    radioProxy15.setDataProfile_1_5(rr.mSerial, dpis);
+                } else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
                     // V1.4
                     android.hardware.radio.V1_4.IRadio radioProxy14 =
                             (android.hardware.radio.V1_4.IRadio) radioProxy;
@@ -4759,6 +4843,98 @@
     }
 
     /**
+     * Enable or disable uicc applications on the SIM.
+     *
+     * @param enable whether to enable or disable uicc applications.
+     * @param onCompleteMessage a Message to return to the requester
+     */
+    @Override
+    public void enableUiccApplications(boolean enable, Message onCompleteMessage) {
+        IRadio radioProxy = getRadioProxy(onCompleteMessage);
+        if (radioProxy == null) {
+            Rlog.e(RIL.RILJ_LOG_TAG, "Radio Proxy object is null!");
+            if (onCompleteMessage != null) {
+                AsyncResult.forMessage(onCompleteMessage, null,
+                        CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+                onCompleteMessage.sendToTarget();
+            }
+        }
+
+        if (mRadioVersion.less(RADIO_HAL_VERSION_1_5)) {
+            if (onCompleteMessage != null) {
+                AsyncResult.forMessage(onCompleteMessage, null,
+                        CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+                onCompleteMessage.sendToTarget();
+            }
+            return;
+        }
+
+        android.hardware.radio.V1_5.IRadio radioProxy15 =
+                (android.hardware.radio.V1_5.IRadio) radioProxy;
+
+        RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_UICC_APPLICATIONS,
+                onCompleteMessage, mRILDefaultWorkSource);
+
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+        try {
+            radioProxy15.enableUiccApplications(rr.mSerial, enable);
+        } catch (RemoteException | RuntimeException e) {
+            handleRadioProxyExceptionForRR(rr, "enableUiccApplications", e);
+        }
+    }
+
+    /**
+     * Whether uicc applications are enabled or not.
+     *
+     * @param onCompleteMessage a Message to return to the requester
+     */
+    @Override
+    public void areUiccApplicationsEnabled(Message onCompleteMessage) {
+        IRadio radioProxy = getRadioProxy(onCompleteMessage);
+        if (radioProxy == null) {
+            Rlog.e(RIL.RILJ_LOG_TAG, "Radio Proxy object is null!");
+            if (onCompleteMessage != null) {
+                AsyncResult.forMessage(onCompleteMessage, null,
+                        CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+                onCompleteMessage.sendToTarget();
+            }
+        }
+
+        if (mRadioVersion.less(RADIO_HAL_VERSION_1_5)) {
+            if (onCompleteMessage != null) {
+                AsyncResult.forMessage(onCompleteMessage, null,
+                        CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+                onCompleteMessage.sendToTarget();
+            }
+            return;
+        }
+
+        android.hardware.radio.V1_5.IRadio radioProxy15 =
+                (android.hardware.radio.V1_5.IRadio) radioProxy;
+
+        RILRequest rr = obtainRequest(RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT,
+                onCompleteMessage, mRILDefaultWorkSource);
+
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+        try {
+            radioProxy15.areUiccApplicationsEnabled(rr.mSerial);
+        } catch (RemoteException | RuntimeException e) {
+            handleRadioProxyExceptionForRR(rr, "areUiccApplicationsEnabled", e);
+        }
+    }
+
+    /**
+     * Whether {@link #enableUiccApplications} is supported, which is supported in 1.5 version.
+     */
+    @Override
+    public boolean canToggleUiccApplicationsEnablement() {
+        return getRadioProxy(null) != null && mRadioVersion
+                .greaterOrEqual(RADIO_HAL_VERSION_1_5);
+    }
+
+    /**
      *  Translates EF_SMS status bits to a status value compatible with
      *  SMS AT commands.  See TS 27.005 3.1.
      */
@@ -5680,6 +5856,10 @@
                 return "RIL_REQUEST_ENABLE_MODEM";
             case RIL_REQUEST_GET_MODEM_STATUS:
                 return "RIL_REQUEST_GET_MODEM_STATUS";
+            case RIL_REQUEST_ENABLE_UICC_APPLICATIONS:
+                return "RIL_REQUEST_ENABLE_UICC_APPLICATIONS";
+            case RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT:
+                return "RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT";
             default: return "<unknown request>";
         }
     }
@@ -5793,6 +5973,8 @@
                 return "RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG";
             case RIL_UNSOL_EMERGENCY_NUMBER_LIST:
                 return "RIL_UNSOL_EMERGENCY_NUMBER_LIST";
+            case RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED:
+                return "RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED";
             default:
                 return "<unknown response>";
         }
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index 5d00690..5b98070 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -63,6 +63,7 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_PROACTIVE_COMMAND;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_SESSION_END;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SUPP_SVC_NOTIFICATION;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_VOICE_RADIO_TECH_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOl_CDMA_PRL_CHANGED;
@@ -761,6 +762,17 @@
         mRil.mRilCellInfoListRegistrants.notifyRegistrants(new AsyncResult(null, response, null));
     }
 
+    /** Get unsolicited message for uicc applications enablement changes. */
+    public void uiccApplicationsEnablementChanged(int indicationType, boolean enabled) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) {
+            mRil.unsljLogRet(RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED, enabled);
+        }
+
+        mRil.mUiccApplicationsEnablementRegistrants.notifyResult(enabled);
+    }
+
     /** Incremental network scan results */
     public void networkScanResult(int indicationType,
                                   android.hardware.radio.V1_1.NetworkScanResult result) {
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index da68b69..ea14b40 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -2363,4 +2363,27 @@
     public void setSystemSelectionChannelsResponse(RadioResponseInfo responseInfo) {
         responseVoid(responseInfo);
     }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     */
+    public void enableUiccApplicationsResponse(RadioResponseInfo responseInfo) {
+        responseVoid(responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     * @param enabled whether Uicc applications are enabled.
+     */
+    public void areUiccApplicationsEnabledResponse(RadioResponseInfo responseInfo,
+            boolean enabled) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, enabled);
+            }
+            mRil.processResponseDone(rr, responseInfo, enabled);
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index b3149c2..fc796ca 100755
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -111,7 +111,7 @@
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UiccProfile;
 import com.android.internal.telephony.util.NotificationChannelController;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
@@ -1141,20 +1141,24 @@
                         }
                     }
                 } else {
-                    // If we receive an empty message, it's probably a timeout; if there is no
-                    // pending request, drop it.
-                    if (!mIsPendingCellInfoRequest) break;
-                    // If there is a request pending, we still need to check whether it's a timeout
-                    // for the current request of whether it's leftover from a previous request.
-                    final long curTime = SystemClock.elapsedRealtime();
-                    if ((curTime - mLastCellInfoReqTime) <  CELL_INFO_LIST_QUERY_TIMEOUT) {
-                        break;
+                    synchronized (mPendingCellInfoRequests) {
+                        // If we receive an empty message, it's probably a timeout; if there is no
+                        // pending request, drop it.
+                        if (!mIsPendingCellInfoRequest) break;
+                        // If there is a request pending, we still need to check whether it's a
+                        // timeout for the current request of whether it's leftover from a
+                        // previous request.
+                        final long curTime = SystemClock.elapsedRealtime();
+                        if ((curTime - mLastCellInfoReqTime) <  CELL_INFO_LIST_QUERY_TIMEOUT) {
+                            break;
+                        }
+                        // We've received a legitimate timeout, so something has gone terribly
+                        // wrong.
+                        loge("Timeout waiting for CellInfo; (everybody panic)!");
+                        mLastCellInfoList = null;
+                        // Since the timeout is applicable, fall through and update all synchronous
+                        // callers with the failure.
                     }
-                    // We've received a legitimate timeout, so something has gone terribly wrong.
-                    loge("Timeout waiting for CellInfo; (everybody panic)!");
-                    mLastCellInfoList = null;
-                    // Since the timeout is applicable, fall through and update all synchronous
-                    // callers with the failure.
                 }
                 synchronized (mPendingCellInfoRequests) {
                     // If we have pending requests, then service them. Note that in case of a
@@ -1579,6 +1583,8 @@
                     // Notify NR frequency, NR connection status or bandwidths changed.
                     if (hasChanged) {
                         mPhone.notifyServiceStateChanged(mSS);
+                        TelephonyMetrics.getInstance().writeServiceStateChanged(
+                                mPhone.getPhoneId(), mSS);
                     }
                 }
                 break;
@@ -2153,6 +2159,7 @@
                 int serviceState = regCodeToServiceState(registrationState);
                 int newDataRat = ServiceState.networkTypeToRilRadioTechnology(
                         networkRegState.getAccessNetworkTechnology());
+                boolean nrHasChanged = false;
 
                 if (DBG) {
                     log("handlePollStateResultMessage: PS cellular. " + networkRegState);
@@ -2163,11 +2170,17 @@
                 // (2 or more cells) to a new cell if they camp for emergency service only.
                 if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
                     mLastPhysicalChannelConfigList = null;
-                    updateNrFrequencyRangeFromPhysicalChannelConfigs(null, mNewSS);
+                    nrHasChanged |= updateNrFrequencyRangeFromPhysicalChannelConfigs(null, mNewSS);
                 }
-                updateNrStateFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS);
+                nrHasChanged |= updateNrStateFromPhysicalChannelConfigs(
+                        mLastPhysicalChannelConfigList, mNewSS);
                 setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity());
 
+                if (nrHasChanged) {
+                    TelephonyMetrics.getInstance().writeServiceStateChanged(
+                            mPhone.getPhoneId(), mSS);
+                }
+
                 if (mPhone.isPhoneTypeGsm()) {
 
                     mNewReasonDataDenied = networkRegState.getRejectCause();
@@ -3405,7 +3418,9 @@
             mPhone.getContext().getContentResolver()
                     .insert(getUriForSubscriptionId(mPhone.getSubId()),
                             getContentValuesForServiceState(mSS));
+        }
 
+        if (hasChanged || hasNrStateChanged) {
             TelephonyMetrics.getInstance().writeServiceStateChanged(mPhone.getPhoneId(), mSS);
         }
 
@@ -5211,7 +5226,7 @@
             if (currentServiceState.getVoiceRoaming()) {
                 if (mPhone.isPhoneTypeGsm()) {
                     // check roaming type by MCC
-                    if (inSameCountry(currentServiceState.getVoiceOperatorNumeric())) {
+                    if (inSameCountry(currentServiceState.getOperatorNumeric())) {
                         currentServiceState.setVoiceRoamingType(
                                 ServiceState.ROAMING_TYPE_DOMESTIC);
                     } else {
@@ -5235,7 +5250,7 @@
                         }
                     } else {
                         // check roaming type by MCC
-                        if (inSameCountry(currentServiceState.getVoiceOperatorNumeric())) {
+                        if (inSameCountry(currentServiceState.getOperatorNumeric())) {
                             currentServiceState.setVoiceRoamingType(
                                     ServiceState.ROAMING_TYPE_DOMESTIC);
                         } else {
@@ -5282,7 +5297,7 @@
                         }
                     } else {
                         // take it as 3GPP roaming
-                        if (inSameCountry(currentServiceState.getDataOperatorNumeric())) {
+                        if (inSameCountry(currentServiceState.getOperatorNumeric())) {
                             currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_DOMESTIC);
                         } else {
                             currentServiceState.setDataRoamingType(
diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java
index eaa7fc8..64a5ab9 100644
--- a/src/java/com/android/internal/telephony/SmsController.java
+++ b/src/java/com/android/internal/telephony/SmsController.java
@@ -18,12 +18,11 @@
 
 package com.android.internal.telephony;
 
-import static com.android.internal.util.DumpUtils.checkDumpPermission;
+import static com.android.internal.telephony.util.TelephonyUtils.checkDumpPermission;
 
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
-import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -189,7 +188,7 @@
     private void sendBluetoothText(SubscriptionInfo info, String destAddr,
             String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
         BtSmsInterfaceManager btSmsInterfaceManager = new BtSmsInterfaceManager();
-        btSmsInterfaceManager.sendText(destAddr, text, sentIntent, deliveryIntent, info);
+        btSmsInterfaceManager.sendText(mContext, destAddr, text, sentIntent, deliveryIntent, info);
     }
 
     private void sendIccText(int subId, String callingPackage, String destAddr,
@@ -367,7 +366,7 @@
 
     @Override
     public boolean isSmsSimPickActivityNeeded(int subId) {
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
+        final Context context = mContext.getApplicationContext();
         ActivityManager am = context.getSystemService(ActivityManager.class);
         // Don't show the SMS SIM Pick activity if it is not foreground.
         boolean isCallingProcessForeground = am != null
diff --git a/src/java/com/android/internal/telephony/SmsUsageMonitor.java b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
index 2107963..dadf62e 100644
--- a/src/java/com/android/internal/telephony/SmsUsageMonitor.java
+++ b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
@@ -17,7 +17,6 @@
 package com.android.internal.telephony;
 
 import android.annotation.UnsupportedAppUsage;
-import android.app.AppGlobals;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -27,7 +26,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.PhoneNumberUtils;
@@ -36,8 +34,8 @@
 import android.util.AtomicFile;
 import android.util.Xml;
 
+import com.android.internal.telephony.util.XmlUtils;
 import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index c483836..1ebea33 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -46,6 +46,7 @@
 import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.SimDisplayNameSource;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccAccessRule;
 import android.telephony.UiccSlotInfo;
@@ -62,7 +63,7 @@
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.util.TelephonyUtils;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -1505,30 +1506,27 @@
      * @param nameSource Source of display name
      * @return int representing the priority. Higher value means higher priority.
      */
-    public static int getNameSourcePriority(int nameSource) {
-        switch (nameSource) {
-            case SubscriptionManager.NAME_SOURCE_USER_INPUT:
-                return 3;
-            case SubscriptionManager.NAME_SOURCE_CARRIER:
-                return 2;
-            case SubscriptionManager.NAME_SOURCE_SIM_SOURCE:
-                return 1;
-            case SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE:
-            default:
-                return 0;
-        }
+    public static int getNameSourcePriority(@SimDisplayNameSource int nameSource) {
+        int index = Arrays.asList(
+                SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE,
+                SubscriptionManager.NAME_SOURCE_SIM_PNN,
+                SubscriptionManager.NAME_SOURCE_SIM_SPN,
+                SubscriptionManager.NAME_SOURCE_CARRIER,
+                SubscriptionManager.NAME_SOURCE_USER_INPUT // user has highest priority.
+        ).indexOf(nameSource);
+        return (index < 0) ? 0 : index;
     }
 
     /**
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
      * @param subId the unique SubInfoRecord index in database
-     * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
-     *                   2: NAME_SOURCE_USER_INPUT, 3: NAME_SOURCE_CARRIER
+     * @param nameSource SIM display name source
      * @return the number of records updated
      */
     @Override
-    public int setDisplayNameUsingSrc(String displayName, int subId, int nameSource) {
+    public int setDisplayNameUsingSrc(String displayName, int subId,
+                                      @SimDisplayNameSource int nameSource) {
         if (DBG) {
             logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
                 + " nameSource:" + nameSource);
@@ -1548,6 +1546,10 @@
                         && (getNameSourcePriority(subInfo.getNameSource())
                                 > getNameSourcePriority(nameSource)
                         || (displayName != null && displayName.equals(subInfo.getDisplayName())))) {
+                    logd("Name source " + subInfo.getNameSource() + "'s priority "
+                            + getNameSourcePriority(subInfo.getNameSource()) + " is greater than "
+                            + "name source " + nameSource + "'s priority "
+                            + getNameSourcePriority(nameSource) + ", return now.");
                     return 0;
                 }
             }
@@ -3053,12 +3055,6 @@
             throw new IllegalArgumentException("Invalid groupUuid");
         }
 
-        // TODO: Revisit whether we need this restriction in R. There's no technical need for it,
-        // but we don't want to change the API behavior at this time.
-        if (getSubscriptionsInGroup(groupUuid, callingPackage).isEmpty()) {
-            throw new IllegalArgumentException("Cannot add subscriptions to a non-existent group!");
-        }
-
         // Makes sure calling package matches caller UID.
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         // If it doesn't have modify phone state permission, or carrier privilege permission,
@@ -3313,6 +3309,9 @@
                         "setSubscriptionEnabled not usable subId " + subId);
             }
 
+            // Nothing to do if it's already active or inactive.
+            if (enable == isActiveSubscriptionId(subId)) return true;
+
             SubscriptionInfo info = SubscriptionController.getInstance()
                     .getAllSubInfoList(mContext.getOpPackageName())
                     .stream()
@@ -3325,6 +3324,8 @@
                 return false;
             }
 
+            // TODO: make sure after slot mapping, we enable the uicc applications for the
+            // subscription we are enabling.
             if (info.isEmbedded()) {
                 return enableEmbeddedSubscription(info, enable);
             } else {
@@ -3356,46 +3357,43 @@
         // updateEnabledSubscriptionGlobalSetting(subId, physicalSlotIndex);
     }
 
-    private static boolean isInactiveInsertedPSim(UiccSlotInfo slotInfo, String cardId) {
-        return !slotInfo.getIsEuicc() && !slotInfo.getIsActive()
-                && slotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT
-                && TextUtils.equals(slotInfo.getCardId(), cardId);
-    }
-
     private boolean enablePhysicalSubscription(SubscriptionInfo info, boolean enable) {
-        if (enable && info.getSimSlotIndex() == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            UiccSlotInfo[] slotsInfo = mTelephonyManager.getUiccSlotsInfo();
-            if (slotsInfo == null) return false;
-            boolean foundMatch = false;
-            for (int i = 0; i < slotsInfo.length; i++) {
-                UiccSlotInfo slotInfo = slotsInfo[i];
-                if (isInactiveInsertedPSim(slotInfo, info.getCardString())) {
-                    // We need to send intents to Euicc if we are turning on an inactive pSIM.
-                    // Euicc will decide whether to ask user to switch to DSDS, or change SIM
-                    // slot mapping.
-                    enableSubscriptionOverEuiccManager(info.getSubscriptionId(), enable, i);
-                    foundMatch = true;
-                    break;
-                }
-            }
-
-            if (!foundMatch) {
-                logdl("enablePhysicalSubscription subId " + info.getSubscriptionId()
-                        + " is not inserted.");
-            }
-            // returning false to indicate state is not changed yet. If intent is sent to LPA and
-            // user consents switching, caller needs to listen to subscription info change.
+        if (info == null || !SubscriptionManager.isValidSubscriptionId(info.getSubscriptionId())) {
             return false;
-        } else {
-            return mTelephonyManager.enableModemForSlot(info.getSimSlotIndex(), enable);
         }
 
-        // TODO: uncomment or clean up if we decide whether to support standalone CBRS for Q.
-        // updateEnabledSubscriptionGlobalSetting(
-        //        enable ? subId : SubscriptionManager.INVALID_SUBSCRIPTION_ID,
-        //        physicalSlotIndex);
-        // updateModemStackEnabledGlobalSetting(enable, physicalSlotIndex);
-        // refreshCachedActiveSubscriptionInfoList();
+        int subId = info.getSubscriptionId();
+
+        UiccSlotInfo slotInfo = null;
+        int physicalSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+        UiccSlotInfo[] slotsInfo = mTelephonyManager.getUiccSlotsInfo();
+        if (slotsInfo == null) return false;
+        for (int i = 0; i < slotsInfo.length; i++) {
+            UiccSlotInfo curSlotInfo = slotsInfo[i];
+            if (curSlotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT
+                    && TextUtils.equals(curSlotInfo.getCardId(), info.getCardString())) {
+                slotInfo = curSlotInfo;
+                physicalSlotIndex = i;
+                break;
+            }
+        }
+
+        // Can't find the existing SIM.
+        if (slotInfo == null) return false;
+
+        if (enable && !slotInfo.getIsActive()) {
+            // We need to send intents to Euicc if we are turning on an inactive slot.
+            // Euicc will decide whether to ask user to switch to DSDS, or change SIM
+            // slot mapping.
+            enableSubscriptionOverEuiccManager(subId, enable, physicalSlotIndex);
+            return true;
+        } else {
+            // Enable / disable uicc applications.
+            Phone phone = PhoneFactory.getPhone(slotInfo.getLogicalSlotIdx());
+            if (phone == null) return false;
+            phone.enableUiccApplications(enable, null);
+            return true;
+        }
     }
 
     private void enableSubscriptionOverEuiccManager(int subId, boolean enable,
@@ -3774,8 +3772,8 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            // TODO: b/133379187
-            return false;
+            Phone phone = PhoneFactory.getDefaultPhone();
+            return phone != null && phone.canDisablePhysicalSubscription();
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/src/java/com/android/internal/telephony/cdma/EriManager.java b/src/java/com/android/internal/telephony/cdma/EriManager.java
index eb19963..4ef55eb 100644
--- a/src/java/com/android/internal/telephony/cdma/EriManager.java
+++ b/src/java/com/android/internal/telephony/cdma/EriManager.java
@@ -26,8 +26,7 @@
 import android.util.Xml;
 
 import com.android.internal.telephony.Phone;
-import com.android.internal.util.XmlUtils;
-
+import com.android.internal.telephony.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index a26b561..f345429 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -591,6 +591,10 @@
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_MCX;
         }
+        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) {
+            if (apnType != ApnSetting.TYPE_NONE) error = true;
+            apnType = ApnSetting.TYPE_XCAP;
+        }
         if (error) {
             // TODO: If this error condition is removed, the framework's handling of
             // NET_CAPABILITY_NOT_RESTRICTED will need to be updated so requests for
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index cb4853e..658ba6e 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -417,7 +417,8 @@
         return getCurrentState() == mDisconnectingState;
     }
 
-    boolean isActive() {
+    @VisibleForTesting
+    public boolean isActive() {
         return getCurrentState() == mActiveState;
     }
 
@@ -1264,6 +1265,10 @@
                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX);
                         break;
                     }
+                    case PhoneConstants.APN_TYPE_XCAP: {
+                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
+                        break;
+                    }
                     default:
                 }
             }
@@ -2086,7 +2091,7 @@
 
                 mDisabledApnTypeBitMask |= getDisallowedApnTypes();
 
-                mNetworkAgent = DcNetworkAgent.createDcNetworkAgent(DataConnection.this,
+                mNetworkAgent = new DcNetworkAgent(DataConnection.this,
                         mPhone, mNetworkInfo, mScore, misc, factorySerialNumber, mTransportType);
             }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
index ae773bb..87152f2 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
@@ -34,11 +34,11 @@
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This class represents a network agent which is communication channel between
@@ -65,23 +65,20 @@
 
     private final LocalLog mNetCapsLocalLog = new LocalLog(50);
 
-    private static AtomicInteger sSerialNumber = new AtomicInteger(0);
-
     private NetworkInfo mNetworkInfo;
 
-    private DcNetworkAgent(DataConnection dc, String tag, Phone phone, NetworkInfo ni,
-                           int score, NetworkMisc misc, int factorySerialNumber,
-                           int transportType) {
-        super(dc.getHandler().getLooper(), phone.getContext(), tag, ni,
+    DcNetworkAgent(DataConnection dc, Phone phone, NetworkInfo ni, int score, NetworkMisc misc,
+                   int factorySerialNumber, int transportType) {
+        super(dc.getHandler().getLooper(), phone.getContext(), "DcNetworkAgent", ni,
                 dc.getNetworkCapabilities(), dc.getLinkProperties(), score, misc,
                 factorySerialNumber);
-        mTag = tag;
+        mTag = "DcNetworkAgent" + "-" + netId;
         mPhone = phone;
         mNetworkCapabilities = dc.getNetworkCapabilities();
         mTransportType = transportType;
         mDataConnection = dc;
         mNetworkInfo = ni;
-        logd(tag + " created for data connection " + dc.getName());
+        logd(mTag + " created for data connection " + dc.getName());
     }
 
     /**
@@ -92,28 +89,6 @@
     }
 
     /**
-     * Constructor
-     *
-     * @param dc The data connection owns this network agent.
-     * @param phone The phone object.
-     * @param ni Network info.
-     * @param score Score of the data connection.
-     * @param misc The miscellaneous information of the data connection.
-     * @param factorySerialNumber Serial number of telephony network factory.
-     * @param transportType The transport of the data connection.
-     * @return The network agent
-     */
-    public static DcNetworkAgent createDcNetworkAgent(DataConnection dc, Phone phone,
-                                                      NetworkInfo ni, int score, NetworkMisc misc,
-                                                      int factorySerialNumber, int transportType) {
-        // Use serial number only. Do not use transport type because it can be transferred to
-        // a different transport.
-        String tag = "DcNetworkAgent-" + sSerialNumber.incrementAndGet();
-        return new DcNetworkAgent(dc, tag, phone, ni, score, misc, factorySerialNumber,
-                transportType);
-    }
-
-    /**
      * Set the data connection that owns this network agent.
      *
      * @param dc Data connection owning this network agent.
@@ -216,6 +191,14 @@
                     + ", dc=" + mDataConnection.getName();
             logd(logStr);
             mNetCapsLocalLog.log(logStr);
+            if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                // only log metrics for DataConnection with NET_CAPABILITY_INTERNET
+                if (mNetworkCapabilities == null
+                        || networkCapabilities.isMetered() != mNetworkCapabilities.isMetered()) {
+                    TelephonyMetrics.getInstance().writeNetworkCapabilitiesChangedEvent(
+                            mPhone.getPhoneId(), networkCapabilities);
+                }
+            }
             mNetworkCapabilities = networkCapabilities;
         }
         sendNetworkCapabilities(networkCapabilities);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index b4500c6..8acd9de 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -108,7 +108,7 @@
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccController;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.AsyncChannel;
 
 import java.io.FileDescriptor;
@@ -152,8 +152,9 @@
     private static final int NETWORK_TYPE_CBS = ConnectivityManager.TYPE_MOBILE_CBS;
     private static final int NETWORK_TYPE_IA = ConnectivityManager.TYPE_MOBILE_IA;
     private static final int NETWORK_TYPE_EMERGENCY = ConnectivityManager.TYPE_MOBILE_EMERGENCY;
-    private static final int NETWORK_TYPE_MCX = 1001;  // far away from ConnectivityManager.TYPE_xxx
-                                                       // constants as MCX isn't defined there.
+    // far away from ConnectivityManager.TYPE_xxx constants as the APNs below aren't defined there.
+    private static final int NETWORK_TYPE_MCX = 1001;
+    private static final int NETWORK_TYPE_XCAP = 1002;
 
     @IntDef(value = {
             REQUEST_TYPE_NORMAL,
@@ -1006,6 +1007,9 @@
                 case NETWORK_TYPE_MCX:
                     apnContext = addApnContext(PhoneConstants.APN_TYPE_MCX, networkConfig);
                     break;
+                case NETWORK_TYPE_XCAP:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_XCAP, networkConfig);
+                    break;
                 default:
                     log("initApnContexts: skipping unknown type=" + networkConfig.type);
                     continue;
diff --git a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
index f391320..7f0c730 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
@@ -347,16 +347,16 @@
                 if (dcTracker != null) {
                     DataConnection dc = dcTracker.getDataConnectionByApnType(
                             ApnSetting.getApnTypeString(apnType));
-                    if (dc != null && (dc.isActive() || dc.isActivating())) {
+                    if (dc != null && (dc.isActive())) {
                         Message onCompleteMsg = mInternalHandler.obtainMessage(
                                 EVENT_DATA_HANDOVER_COMPLETED);
                         onCompleteMsg.getData().putParcelable(
                                 DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST, networkRequest);
                         mPendingHandovers.put(onCompleteMsg, handoverParams);
-                        // TODO: Need to handle the case that the request is there, but there is no
-                        // actual data connections established.
                         requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_HANDOVER,
                                 targetTransport, onCompleteMsg);
+                        log("Requested handover " + ApnSetting.getApnTypeString(apnType) + " to "
+                                + AccessNetworkConstants.transportTypeToString(targetTransport));
                         handoverPending = true;
                     } else {
                         // Request is there, but no actual data connection. In this case, just move
diff --git a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
index c61bbe2..6a2af7c 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
@@ -38,7 +38,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RIL;
 import com.android.internal.telephony.dataconnection.AccessNetworksManager.QualifiedNetworks;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
diff --git a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
index 7b5dd0c..c258a81 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
@@ -130,7 +130,7 @@
             if (sEnableCbModule) {
                 mCellBroadcastServiceManager.sendGsmMessageToHandler(m);
             } else {
-                m.setWhat(GsmCellBroadcastHandler.EVENT_NEW_SMS_MESSAGE);
+                m.what = GsmCellBroadcastHandler.EVENT_NEW_SMS_MESSAGE;
                 mCellBroadcastHandler.sendMessage(m);
             }
         }
diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 01ba6ad..b3c071b 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -53,7 +53,7 @@
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccCardApplication;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 
 import dalvik.annotation.compat.UnsupportedAppUsage;
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 34b4f3b..d70bee3 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -99,13 +99,13 @@
 import com.android.internal.telephony.LocaleTracker;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.PhoneInternalInterface;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.dataconnection.DataEnabledSettings;
 import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs;
 import com.android.internal.telephony.metrics.CallQualityMetrics;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
@@ -319,6 +319,7 @@
     private static final int EVENT_REDIAL_WIFI_E911_TIMEOUT = 29;
     private static final int EVENT_ANSWER_WAITING_CALL = 30;
     private static final int EVENT_RESUME_NOW_FOREGROUND_CALL = 31;
+    private static final int EVENT_REDIAL_WITHOUT_RTT = 32;
 
     private static final int TIMEOUT_HANGUP_PENDINGMO = 500;
 
@@ -442,7 +443,8 @@
     private HoldSwapState mHoldSwitchingState = HoldSwapState.INACTIVE;
 
     private String mLastDialString = null;
-    private PhoneInternalInterface.DialArgs mLastDialArgs = null;
+    private ImsDialArgs mLastDialArgs = null;
+
     /**
      * Listeners to changes in the phone state.  Intended for use by other interested IMS components
      * without the need to register a full blown {@link android.telephony.PhoneStateListener}.
@@ -2459,6 +2461,10 @@
                         .getSystemService(Context.CONNECTIVITY_SERVICE);
                 mgr.setAirplaneMode(false);
                 return;
+            } else if (reasonInfo.getCode() == ImsReasonInfo.CODE_RETRY_ON_IMS_WITHOUT_RTT) {
+                Pair<ImsCall, ImsReasonInfo> callInfo = new Pair<>(imsCall, reasonInfo);
+                sendMessage(obtainMessage(EVENT_REDIAL_WITHOUT_RTT, callInfo));
+                return;
             } else {
                 processCallStateChange(imsCall, ImsPhoneCall.State.DISCONNECTED, cause);
             }
@@ -3527,6 +3533,30 @@
                 sendCallStartFailedDisconnect(callInfo.first, callInfo.second);
                 break;
             }
+
+            case EVENT_REDIAL_WITHOUT_RTT: {
+                Pair<ImsCall, ImsReasonInfo> callInfo = (Pair<ImsCall, ImsReasonInfo>) msg.obj;
+                removeMessages(EVENT_REDIAL_WITHOUT_RTT);
+                ImsPhoneConnection oldConnection = findConnection(callInfo.first);
+                if (oldConnection == null) {
+                    sendCallStartFailedDisconnect(callInfo.first, callInfo.second);
+                    break;
+                }
+                mForegroundCall.detach(oldConnection);
+                removeConnection(oldConnection);
+                try {
+                    mPendingMO = null;
+                    ImsDialArgs newDialArgs = ImsDialArgs.Builder.from(mLastDialArgs)
+                            .setRttTextStream(null)
+                            .build();
+                    Connection newConnection =
+                            mPhone.getDefaultPhone().dial(mLastDialString, newDialArgs);
+                    oldConnection.onOriginalConnectionReplaced(newConnection);
+                } catch (CallStateException e) {
+                    sendCallStartFailedDisconnect(callInfo.first, callInfo.second);
+                }
+                break;
+            }
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java b/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java
index a3f287c..d882993 100644
--- a/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java
@@ -31,6 +31,7 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * CallQualityMetrics is a utility for tracking the CallQuality during an ongoing call session. It
@@ -63,6 +64,12 @@
     // the first MAX_SNAPSHOTS transitions between good and bad quality
     private ArrayList<Pair<CallQuality, Integer>> mDlSnapshots = new ArrayList<>();
 
+    // holds lightweight history of call quality and durations, used for calculating total time
+    // spent with bad and good quality for metrics and bugreports. This is separate from the
+    // snapshots because those are capped at MAX_SNAPSHOTS to avoid excessive memory use.
+    private ArrayList<TimestampedQualitySnapshot> mFullUplinkQuality = new ArrayList<>();
+    private ArrayList<TimestampedQualitySnapshot> mFullDownlinkQuality = new ArrayList<>();
+
     // Current downlink call quality
     private int mDlCallQualityState = GOOD_QUALITY;
 
@@ -72,7 +79,7 @@
     // The last logged CallQuality
     private CallQuality mLastCallQuality;
 
-    /** Snapshots taken at best and worst SignalStrengths*/
+    /** Snapshots taken at best and worst SignalStrengths */
     private Pair<CallQuality, Integer> mWorstSsWithGoodDlQuality;
     private Pair<CallQuality, Integer> mBestSsWithGoodDlQuality;
     private Pair<CallQuality, Integer> mWorstSsWithBadDlQuality;
@@ -82,12 +89,6 @@
     private Pair<CallQuality, Integer> mWorstSsWithBadUlQuality;
     private Pair<CallQuality, Integer> mBestSsWithBadUlQuality;
 
-    /** Total durations of good and bad quality time for uplink and downlink */
-    private int mTotalDlGoodQualityTimeMs = 0;
-    private int mTotalDlBadQualityTimeMs = 0;
-    private int mTotalUlGoodQualityTimeMs = 0;
-    private int mTotalUlBadQualityTimeMs = 0;
-
     /**
      * Construct a CallQualityMetrics object to be used to keep track of call quality for a single
      * call session.
@@ -118,20 +119,30 @@
 
         if (USERDEBUG_MODE) {
             if (newUlCallQualityState != mUlCallQualityState) {
-                mUlSnapshots = addSnapshot(cq, mUlSnapshots);
+                addSnapshot(cq, mUlSnapshots);
             }
             if (newDlCallQualityState != mDlCallQualityState) {
-                mDlSnapshots = addSnapshot(cq, mDlSnapshots);
+                addSnapshot(cq, mDlSnapshots);
             }
         }
 
-        updateTotalDurations(newDlCallQualityState, newUlCallQualityState, cq);
+        updateTotalDurations(cq);
 
         updateMinAndMaxSignalStrengthSnapshots(newDlCallQualityState, newUlCallQualityState, cq);
 
         mUlCallQualityState = newUlCallQualityState;
         mDlCallQualityState = newDlCallQualityState;
-        mLastCallQuality = cq;
+        // call duration updates sometimes come out of order
+        if (cq.getCallDuration() > mLastCallQuality.getCallDuration()) {
+            mLastCallQuality = cq;
+        }
+    }
+
+    private void updateTotalDurations(CallQuality cq) {
+        mFullDownlinkQuality.add(new TimestampedQualitySnapshot(cq.getCallDuration(),
+                cq.getDownlinkCallQualityLevel()));
+        mFullUplinkQuality.add(new TimestampedQualitySnapshot(cq.getCallDuration(),
+                cq.getUplinkCallQualityLevel()));
     }
 
     private static boolean isGoodQuality(int callQualityLevel) {
@@ -142,32 +153,11 @@
      * Save a snapshot of the call quality and signal strength. This can be called with uplink or
      * downlink call quality level.
      */
-    private ArrayList<Pair<CallQuality, Integer>> addSnapshot(CallQuality cq,
-            ArrayList<Pair<CallQuality, Integer>> snapshots) {
+    private void addSnapshot(CallQuality cq, ArrayList<Pair<CallQuality, Integer>> snapshots) {
         if (snapshots.size() < MAX_SNAPSHOTS) {
             Integer ss = getLteSnr();
             snapshots.add(Pair.create(cq, ss));
         }
-        return snapshots;
-    }
-
-    /**
-     * Updates the running total duration of good and bad call quality for uplink and downlink.
-     */
-    private void updateTotalDurations(int newDlCallQualityState, int newUlCallQualityState,
-            CallQuality cq) {
-        int timePassed = cq.getCallDuration() - mLastCallQuality.getCallDuration();
-        if (newDlCallQualityState == GOOD_QUALITY) {
-            mTotalDlGoodQualityTimeMs += timePassed;
-        } else {
-            mTotalDlBadQualityTimeMs += timePassed;
-        }
-
-        if (newUlCallQualityState == GOOD_QUALITY) {
-            mTotalUlGoodQualityTimeMs += timePassed;
-        } else {
-            mTotalUlBadQualityTimeMs += timePassed;
-        }
     }
 
     /**
@@ -261,8 +251,10 @@
     public TelephonyCallSession.Event.CallQualitySummary getCallQualitySummaryDl() {
         TelephonyCallSession.Event.CallQualitySummary summary =
                 new TelephonyCallSession.Event.CallQualitySummary();
-        summary.totalGoodQualityDurationInSeconds = mTotalDlGoodQualityTimeMs / 1000;
-        summary.totalBadQualityDurationInSeconds = mTotalDlBadQualityTimeMs / 1000;
+        Pair<Integer, Integer> totalGoodAndBadDurations = getTotalGoodAndBadQualityTimeMs(
+                mFullDownlinkQuality);
+        summary.totalGoodQualityDurationInSeconds = totalGoodAndBadDurations.first / 1000;
+        summary.totalBadQualityDurationInSeconds = totalGoodAndBadDurations.second / 1000;
         // This value could be different from mLastCallQuality.getCallDuration if we support
         // handover from IMS->CS->IMS, but this is currently not possible
         // TODO(b/130302396) this also may be possible when we put a call on hold and continue with
@@ -299,8 +291,10 @@
     public TelephonyCallSession.Event.CallQualitySummary getCallQualitySummaryUl() {
         TelephonyCallSession.Event.CallQualitySummary summary =
                 new TelephonyCallSession.Event.CallQualitySummary();
-        summary.totalGoodQualityDurationInSeconds = mTotalUlGoodQualityTimeMs / 1000;
-        summary.totalBadQualityDurationInSeconds = mTotalUlBadQualityTimeMs / 1000;
+        Pair<Integer, Integer> totalGoodAndBadDurations = getTotalGoodAndBadQualityTimeMs(
+                mFullUplinkQuality);
+        summary.totalGoodQualityDurationInSeconds = totalGoodAndBadDurations.first / 1000;
+        summary.totalBadQualityDurationInSeconds = totalGoodAndBadDurations.second / 1000;
         // This value could be different from mLastCallQuality.getCallDuration if we support
         // handover from IMS->CS->IMS, but this is currently not possible
         // TODO(b/130302396) this also may be possible when we put a call on hold and continue with
@@ -331,6 +325,60 @@
         return summary;
     }
 
+
+    /**
+     * Container class for call quality level and signal strength at the time of snapshot. This
+     * class implements compareTo so that it can be sorted by timestamp
+     */
+    private class TimestampedQualitySnapshot implements Comparable<TimestampedQualitySnapshot> {
+        int mTimestampMs;
+        int mCallQualityLevel;
+
+        TimestampedQualitySnapshot(int timestamp, int cq) {
+            mTimestampMs = timestamp;
+            mCallQualityLevel = cq;
+        }
+
+        @Override
+        public int compareTo(TimestampedQualitySnapshot o) {
+            return this.mTimestampMs - o.mTimestampMs;
+        }
+
+        @Override
+        public String toString() {
+            return "mTimestampMs=" + mTimestampMs + " mCallQualityLevel=" + mCallQualityLevel;
+        }
+    }
+
+    /**
+     * Use a list of snapshots to calculate and return the total time spent in a call with good
+     * quality and bad quality.
+     * This is slightly expensive since it involves sorting the snapshots by timestamp.
+     *
+     * @param snapshots a list of uplink or downlink snapshots
+     * @return a pair where the first element is the total good quality time and the second element
+     * is the total bad quality time
+     */
+    private Pair<Integer, Integer> getTotalGoodAndBadQualityTimeMs(
+            ArrayList<TimestampedQualitySnapshot> snapshots) {
+        int totalGoodQualityTime = 0;
+        int totalBadQualityTime = 0;
+        int lastTimestamp = 0;
+        // sort by timestamp using TimestampedQualitySnapshot.compareTo
+        Collections.sort(snapshots);
+        for (TimestampedQualitySnapshot snapshot : snapshots) {
+            int timeSinceLastSnapshot = snapshot.mTimestampMs - lastTimestamp;
+            if (isGoodQuality(snapshot.mCallQualityLevel)) {
+                totalGoodQualityTime += timeSinceLastSnapshot;
+            } else {
+                totalBadQualityTime += timeSinceLastSnapshot;
+            }
+            lastTimestamp = snapshot.mTimestampMs;
+        }
+
+        return Pair.create(totalGoodQualityTime, totalBadQualityTime);
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -355,14 +403,16 @@
         }
         sb.append("}");
         sb.append(" ");
-        sb.append(" mTotalDlGoodQualityTimeMs: ");
-        sb.append(mTotalDlGoodQualityTimeMs);
-        sb.append(" mTotalDlBadQualityTimeMs: ");
-        sb.append(mTotalDlBadQualityTimeMs);
-        sb.append(" mTotalUlGoodQualityTimeMs: ");
-        sb.append(mTotalUlGoodQualityTimeMs);
-        sb.append(" mTotalUlBadQualityTimeMs: ");
-        sb.append(mTotalUlBadQualityTimeMs);
+        Pair<Integer, Integer> dlTotals = getTotalGoodAndBadQualityTimeMs(mFullDownlinkQuality);
+        Pair<Integer, Integer> ulTotals = getTotalGoodAndBadQualityTimeMs(mFullUplinkQuality);
+        sb.append(" TotalDlGoodQualityTimeMs: ");
+        sb.append(dlTotals.first);
+        sb.append(" TotalDlBadQualityTimeMs: ");
+        sb.append(dlTotals.second);
+        sb.append(" TotalUlGoodQualityTimeMs: ");
+        sb.append(ulTotals.first);
+        sb.append(" TotalUlBadQualityTimeMs: ");
+        sb.append(ulTotals.second);
         sb.append("]");
         return sb.toString();
     }
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
index 73439c3..658fe5c 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
@@ -25,6 +25,7 @@
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.NetworkCapabilitiesInfo;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
@@ -209,4 +210,12 @@
         mEvent.onDemandDataSwitch = onDemandDataSwitch;
         return this;
     }
+
+    /** Set and build network capabilities changed event. */
+    public TelephonyEventBuilder setNetworkCapabilities(
+            NetworkCapabilitiesInfo networkCapabilities) {
+        mEvent.type = TelephonyEvent.Type.NETWORK_CAPABILITIES_CHANGED;
+        mEvent.networkCapabilities = networkCapabilities;
+        return this;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index 2674290..4bf0d10 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -37,6 +37,7 @@
 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_UNSTRUCTURED;
 import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_UNKNOWN;
 
+import android.net.NetworkCapabilities;
 import android.os.Build;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -72,7 +73,6 @@
 import com.android.internal.telephony.RIL;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.SmsResponse;
-import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.telephony.UUSInfo;
 import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.nano.TelephonyProto;
@@ -94,6 +94,7 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.NetworkCapabilitiesInfo;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall.DeactivateReason;
@@ -105,6 +106,7 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
 import com.android.internal.telephony.nano.TelephonyProto.TimeInterval;
 import com.android.internal.telephony.protobuf.nano.MessageNano;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
@@ -207,6 +209,12 @@
     private final SparseArray<CarrierIdMatching> mLastCarrierId = new SparseArray<>();
 
     /**
+     * Last NetworkCapabilitiesInfo, indexed by phone id.
+     */
+    private final SparseArray<NetworkCapabilitiesInfo> mLastNetworkCapabilitiesInfos =
+            new SparseArray<>();
+
+    /**
      * Last RilDataCall Events (indexed by cid), indexed by phone id
      */
     private final SparseArray<SparseArray<RilDataCall>> mLastRilDataCallEvents =
@@ -314,6 +322,8 @@
                 return "NITZ_TIME";
             case TelephonyEvent.Type.EMERGENCY_NUMBER_REPORT:
                 return "EMERGENCY_NUMBER_REPORT";
+            case TelephonyEvent.Type.NETWORK_CAPABILITIES_CHANGED:
+                return "NETWORK_CAPABILITIES_CHANGED";
             default:
                 return Integer.toString(event);
         }
@@ -434,6 +444,8 @@
                         + "(" + "Data RAT " + event.serviceState.dataRat
                         + " Voice RAT " + event.serviceState.voiceRat
                         + " Channel Number " + event.serviceState.channelNumber
+                        + " NR Frequency Range " + event.serviceState.nrFrequencyRange
+                        + " NR State " + event.serviceState.nrState
                         + ")");
             } else {
                 pw.print(telephonyEventToString(event.type));
@@ -463,6 +475,8 @@
                             + "(" + "Data RAT " + event.serviceState.dataRat
                             + " Voice RAT " + event.serviceState.voiceRat
                             + " Channel Number " + event.serviceState.channelNumber
+                            + " NR Frequency Range " + event.serviceState.nrFrequencyRange
+                            + " NR State " + event.serviceState.nrState
                             + ")");
                 } else if (event.type == TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) {
                     pw.println(callSessionEventToString(event.type));
@@ -648,6 +662,13 @@
             addTelephonyEvent(event);
         }
 
+        for (int i = 0; i < mLastNetworkCapabilitiesInfos.size(); i++) {
+            final int key = mLastNetworkCapabilitiesInfos.keyAt(i);
+            TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
+                    .setNetworkCapabilities(mLastNetworkCapabilitiesInfos.get(key)).build();
+            addTelephonyEvent(event);
+        }
+
         for (int i = 0; i < mLastRilDataCallEvents.size(); i++) {
             final int key = mLastRilDataCallEvents.keyAt(i);
             for (int j = 0; j < mLastRilDataCallEvents.get(key).size(); j++) {
@@ -882,36 +903,27 @@
         ssProto.dataRoamingType = serviceState.getDataRoamingType();
 
         ssProto.voiceOperator = new TelephonyServiceState.TelephonyOperator();
-
-        if (serviceState.getVoiceOperatorAlphaLong() != null) {
-            ssProto.voiceOperator.alphaLong = serviceState.getVoiceOperatorAlphaLong();
-        }
-
-        if (serviceState.getVoiceOperatorAlphaShort() != null) {
-            ssProto.voiceOperator.alphaShort = serviceState.getVoiceOperatorAlphaShort();
-        }
-
-        if (serviceState.getVoiceOperatorNumeric() != null) {
-            ssProto.voiceOperator.numeric = serviceState.getVoiceOperatorNumeric();
-        }
-
         ssProto.dataOperator = new TelephonyServiceState.TelephonyOperator();
-
-        if (serviceState.getDataOperatorAlphaLong() != null) {
-            ssProto.dataOperator.alphaLong = serviceState.getDataOperatorAlphaLong();
+        if (serviceState.getOperatorAlphaLong() != null) {
+            ssProto.voiceOperator.alphaLong = serviceState.getOperatorAlphaLong();
+            ssProto.dataOperator.alphaLong = serviceState.getOperatorAlphaLong();
         }
 
-        if (serviceState.getDataOperatorAlphaShort() != null) {
-            ssProto.dataOperator.alphaShort = serviceState.getDataOperatorAlphaShort();
+        if (serviceState.getOperatorAlphaShort() != null) {
+            ssProto.voiceOperator.alphaShort = serviceState.getOperatorAlphaShort();
+            ssProto.dataOperator.alphaShort = serviceState.getOperatorAlphaShort();
         }
 
-        if (serviceState.getDataOperatorNumeric() != null) {
-            ssProto.dataOperator.numeric = serviceState.getDataOperatorNumeric();
+        if (serviceState.getOperatorNumeric() != null) {
+            ssProto.voiceOperator.numeric = serviceState.getOperatorNumeric();
+            ssProto.dataOperator.numeric = serviceState.getOperatorNumeric();
         }
 
         ssProto.voiceRat = serviceState.getRilVoiceRadioTechnology();
         ssProto.dataRat = serviceState.getRilDataRadioTechnology();
         ssProto.channelNumber = serviceState.getChannelNumber();
+        ssProto.nrFrequencyRange = serviceState.getNrFrequencyRange();
+        ssProto.nrState = serviceState.getNrState();
         return ssProto;
     }
 
@@ -2510,6 +2522,24 @@
     }
 
     /**
+     * Write network capabilities changed event
+     *
+     * @param phoneId Phone id
+     * @param networkCapabilities Network capabilities
+     */
+    public void writeNetworkCapabilitiesChangedEvent(int phoneId,
+            NetworkCapabilities networkCapabilities) {
+        final NetworkCapabilitiesInfo caps = new NetworkCapabilitiesInfo();
+        caps.isNetworkUnmetered = networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+
+        TelephonyEvent event = new TelephonyEventBuilder(phoneId)
+                .setNetworkCapabilities(caps).build();
+        mLastNetworkCapabilitiesInfos.put(phoneId, caps);
+        addTelephonyEvent(event);
+    }
+
+    /**
      * Convert SMS format
      */
     private int convertSmsFormat(String format) {
diff --git a/src/java/com/android/internal/telephony/test/TestConferenceEventPackageParser.java b/src/java/com/android/internal/telephony/test/TestConferenceEventPackageParser.java
index 62c2a77..8df7709 100644
--- a/src/java/com/android/internal/telephony/test/TestConferenceEventPackageParser.java
+++ b/src/java/com/android/internal/telephony/test/TestConferenceEventPackageParser.java
@@ -16,16 +16,16 @@
 
 package com.android.internal.telephony.test;
 
+import android.os.Bundle;
 import android.telephony.ims.ImsConferenceState;
-import com.android.internal.util.XmlUtils;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.internal.telephony.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.os.Bundle;
-import android.util.Log;
-import android.util.Xml;
-
 import java.io.IOException;
 import java.io.InputStream;
 
diff --git a/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java b/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
index 61379d2..d098cff 100644
--- a/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
+++ b/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
@@ -20,7 +20,7 @@
 import android.telephony.Rlog;
 import android.util.Xml;
 
-import com.android.internal.util.XmlUtils;
+import com.android.internal.telephony.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java
index 0307363..c305263 100644
--- a/src/java/com/android/internal/telephony/uicc/IccRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java
@@ -33,7 +33,7 @@
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.MccTable;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index d5a2f94..376977e 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -372,8 +372,8 @@
         String ccName = config.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING);
 
         String newCarrierName = null;
-        String currSpn = getServiceProviderName();
-        int nameSource = SubscriptionManager.NAME_SOURCE_SIM_SOURCE;
+        String currSpn = getServiceProviderName();  // Get the name from EF_SPN.
+        int nameSource = SubscriptionManager.NAME_SOURCE_SIM_SPN;
         // If carrier config is priority, use it regardless - the preference
         // and the name were both set by the carrier, so this is safe;
         // otherwise, if the SPN is priority but we don't have one *and* we have
@@ -382,10 +382,18 @@
             newCarrierName = ccName;
             nameSource = SubscriptionManager.NAME_SOURCE_CARRIER;
         } else if (TextUtils.isEmpty(currSpn)) {
-            // currSpn is empty and could not get name from carrier config; get name from carrier id
+            // currSpn is empty and could not get name from carrier config; get name from PNN or
+            // carrier id
             Phone phone = PhoneFactory.getPhone(mPhoneId);
             if (phone != null) {
-                newCarrierName = phone.getCarrierName();
+                String currPnn = phone.getPlmn();   // Get the name from EF_PNN.
+                if (!TextUtils.isEmpty(currPnn)) {
+                    newCarrierName = currPnn;
+                    nameSource = SubscriptionManager.NAME_SOURCE_SIM_PNN;
+                } else {
+                    newCarrierName = phone.getCarrierName();    // Get the name from carrier id.
+                    nameSource = SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+                }
             }
         }
 
diff --git a/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java b/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java
index b3bdf14..0839758 100644
--- a/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java
+++ b/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java
@@ -18,19 +18,19 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.os.Environment;
-import android.util.Xml;
 import android.telephony.Rlog;
+import android.util.Xml;
 
-import java.util.HashMap;
-import java.io.FileReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
+import com.android.internal.telephony.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import com.android.internal.util.XmlUtils;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/util/TelephonyUtils.java b/src/java/com/android/internal/telephony/util/TelephonyUtils.java
index 518aece..0105577 100644
--- a/src/java/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/src/java/com/android/internal/telephony/util/TelephonyUtils.java
@@ -17,25 +17,44 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
 import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 
+import java.io.PrintWriter;
+
 /**
  * This class provides various util functions
  */
 public final class TelephonyUtils {
     public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
 
+    /**
+     * Verify that caller holds {@link android.Manifest.permission#DUMP}.
+     *
+     * @return true if access should be granted.
+     */
+    public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+        if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump " + tag + " from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " due to missing android.permission.DUMP permission");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
     /** {@hide} */
     public static String emptyIfNull(@Nullable String str) {
         return str == null ? "" : str;
     }
 
-    public static boolean IS_DEBUGGABLE =
-            SystemProperties.getInt("ro.debuggable", 0) == 1;
-
     /** {@hide} */
     public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) {
         throw new RuntimeException(remoteException);
@@ -47,4 +66,7 @@
         if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo;
         throw new IllegalStateException("Missing ComponentInfo!");
     }
-  }
+
+    public static boolean IS_DEBUGGABLE =
+            SystemProperties.getInt("ro.debuggable", 0) == 1;
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastIntentsTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastIntentsTest.java
new file mode 100644
index 0000000..956e8dc
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastIntentsTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.content.Intent;
+import android.os.UserHandle;
+import android.telephony.CellBroadcastIntents;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class CellBroadcastIntentsTest extends TelephonyTest {
+
+    private static final String TEST_ACTION = "test_action";
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp("CellBroadcastIntentsTest");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Verifies that the intent we pass into CellBroadcastIntents
+     * .sendOrderedBroadcastForBackgroundReceivers
+     * is not modified within the function.
+     */
+    @Test
+    public void testIntentIsNotMutated() {
+        Intent originalIntent = new Intent(TEST_ACTION);
+        Intent intentToPass = new Intent(TEST_ACTION);
+        CellBroadcastIntents.sendOrderedBroadcastForBackgroundReceivers(
+                InstrumentationRegistry.getContext(), UserHandle.ALL, intentToPass,
+                null, null, null, null, 0, null, null);
+        assertEquals(originalIntent.getFlags(), intentToPass.getFlags());
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index ae8dd62..e3b325c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.nullable;
 import static org.mockito.Mockito.anyBoolean;
@@ -33,6 +34,7 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -66,6 +68,7 @@
 
 import com.android.internal.telephony.test.SimulatedCommands;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus;
+import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
 import com.android.internal.telephony.uicc.UiccController;
@@ -89,6 +92,10 @@
 public class GsmCdmaPhoneTest extends TelephonyTest {
     @Mock
     private Handler mTestHandler;
+    @Mock
+    private UiccSlot mUiccSlot;
+    @Mock
+    private CommandsInterface mMockCi;
 
     //mPhoneUnderTest
     private GsmCdmaPhone mPhoneUT;
@@ -1197,4 +1204,24 @@
                 CarrierConfigManager.KEY_USE_USIM_BOOL, true);
         assertEquals(msisdn, mPhoneUT.getLine1Number());
     }
+
+    @Test
+    @SmallTest
+    public void testEnableUiccApplications() throws Exception {
+        mPhoneUT.mCi = mMockCi;
+        // UiccSlot is null. Doing nothing.
+        mPhoneUT.enableUiccApplications(true, null);
+        verify(mMockCi, never()).enableUiccApplications(anyBoolean(), any());
+
+        // Card state is not PRESENT. Doing nothing.
+        doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt());
+        doReturn(IccCardStatus.CardState.CARDSTATE_ABSENT).when(mUiccSlot).getCardState();
+        mPhoneUT.enableUiccApplications(true, null);
+        verify(mMockCi, never()).enableUiccApplications(anyBoolean(), any());
+
+        doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState();
+        Message message = Message.obtain();
+        mPhoneUT.enableUiccApplications(true, message);
+        verify(mMockCi).enableUiccApplications(eq(true), eq(message));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index fda30f5..cc1cb2c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -26,6 +26,7 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DELETE_SMS_ON_SIM;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEVICE_IDENTITY;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DTMF;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENABLE_UICC_APPLICATIONS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENTER_SIM_PIN;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENTER_SIM_PIN2;
@@ -40,6 +41,7 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_RADIO_CAPABILITY;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_STATUS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SMSC_ADDRESS;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND;
@@ -82,11 +84,14 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -97,13 +102,13 @@
 import android.hardware.radio.V1_0.CdmaSmsMessage;
 import android.hardware.radio.V1_0.DataProfileInfo;
 import android.hardware.radio.V1_0.GsmSmsMessage;
-import android.hardware.radio.V1_0.IRadio;
 import android.hardware.radio.V1_0.ImsSmsMessage;
 import android.hardware.radio.V1_0.NvWriteItem;
 import android.hardware.radio.V1_0.RadioError;
 import android.hardware.radio.V1_0.RadioResponseInfo;
 import android.hardware.radio.V1_0.RadioResponseType;
 import android.hardware.radio.V1_0.SmsWriteArgs;
+import android.hardware.radio.V1_5.IRadio;
 import android.hardware.radio.deprecated.V1_0.IOemHook;
 import android.net.ConnectivityManager;
 import android.net.LinkAddress;
@@ -177,7 +182,12 @@
     @Mock
     private IOemHook mOemHookProxy;
 
-    private HalVersion mRadioVersion = new HalVersion(1, 0);
+    private HalVersion mRadioVersionV10 = new HalVersion(1, 0);
+    private HalVersion mRadioVersionV11 = new HalVersion(1, 1);
+    private HalVersion mRadioVersionV12 = new HalVersion(1, 2);
+    private HalVersion mRadioVersionV13 = new HalVersion(1, 3);
+    private HalVersion mRadioVersionV14 = new HalVersion(1, 4);
+    private HalVersion mRadioVersionV15 = new HalVersion(1, 5);
 
     private RIL mRILInstance;
     private RIL mRILUnderTest;
@@ -273,7 +283,7 @@
         doReturn(mOemHookProxy).when(mRILUnderTest).getOemHookProxy(any());
 
         try {
-            replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersion);
+            replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV10);
         } catch (Exception e) {
         }
     }
@@ -2000,4 +2010,38 @@
 
         assertTrue(result.equals(expected));
     }
+
+    @Test
+    public void testEnableUiccApplications() throws Exception {
+        // Not supported on Radio 1.0.
+        mRILUnderTest.enableUiccApplications(false, obtainMessage());
+        verify(mRadioProxy, never()).enableUiccApplications(anyInt(), anyBoolean());
+
+        // Make radio version 1.5 to support the operation.
+        try {
+            replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15);
+        } catch (Exception e) {
+        }
+        mRILUnderTest.enableUiccApplications(false, obtainMessage());
+        verify(mRadioProxy).enableUiccApplications(mSerialNumberCaptor.capture(), anyBoolean());
+        verifyRILResponse(mRILUnderTest, mSerialNumberCaptor.getValue(),
+                RIL_REQUEST_ENABLE_UICC_APPLICATIONS);
+    }
+
+    @Test
+    public void testAreUiccApplicationsEnabled() throws Exception {
+        // Not supported on Radio 1.0.
+        mRILUnderTest.areUiccApplicationsEnabled(obtainMessage());
+        verify(mRadioProxy, never()).areUiccApplicationsEnabled(mSerialNumberCaptor.capture());
+
+        // Make radio version 1.5 to support the operation.
+        try {
+            replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15);
+        } catch (Exception e) {
+        }
+        mRILUnderTest.areUiccApplicationsEnabled(obtainMessage());
+        verify(mRadioProxy).areUiccApplicationsEnabled(mSerialNumberCaptor.capture());
+        verifyRILResponse(mRILUnderTest, mSerialNumberCaptor.getValue(),
+                RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
index 60494a8..2d47062 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
@@ -200,19 +200,13 @@
     public void testOperatorName() {
         ServiceState ss = new ServiceState();
 
-        ss.setDataOperatorAlphaLong("abc");
-        assertEquals("abc", ss.getDataOperatorAlphaLong());
-
-        ss.setDataOperatorName("def", "xyz", "123456");
-        assertEquals("xyz", ss.getDataOperatorAlphaShort());
+        ss.setOperatorAlphaLong("abc");
+        assertEquals("abc", ss.getOperatorAlphaLong());
 
         ss.setOperatorName("long", "short", "numeric");
-        assertEquals("long", ss.getVoiceOperatorAlphaLong());
-        assertEquals("short", ss.getVoiceOperatorAlphaShort());
-        assertEquals("numeric", ss.getVoiceOperatorNumeric());
-        assertEquals("long", ss.getDataOperatorAlphaLong());
-        assertEquals("short", ss.getDataOperatorAlphaShort());
-        assertEquals("numeric", ss.getDataOperatorNumeric());
+        assertEquals("long", ss.getOperatorAlphaLong());
+        assertEquals("short", ss.getOperatorAlphaShort());
+        assertEquals("numeric", ss.getOperatorNumeric());
         assertEquals("long", ss.getOperatorAlpha());
 
         ss.setOperatorName("", "short", "");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index 64b0c38..93077e3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -1444,4 +1444,10 @@
     @Override
     public void stopNattKeepalive(int sessionHandle, Message result)  {
     }
+
+    @Override
+    public void registerUiccApplicationEnablementChanged(Handler h, int what, Object obj) {}
+
+    @Override
+    public void unregisterUiccApplicationEnablementChanged(Handler h) {}
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index 75b3534..899ffc8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -60,6 +60,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 public class SubscriptionControllerTest extends TelephonyTest {
     private static final int SINGLE_SIM = 1;
@@ -202,7 +203,7 @@
 
         /* Setting */
         String disName = "TESTING";
-        int nameSource = SubscriptionManager.NAME_SOURCE_SIM_SOURCE;
+        int nameSource = SubscriptionManager.NAME_SOURCE_SIM_SPN;
         mSubscriptionControllerUT.setDisplayNameUsingSrc(disName, subID, nameSource);
         SubscriptionInfo subInfo = mSubscriptionControllerUT
                 .getActiveSubscriptionInfo(subID, mCallingPackage);
@@ -465,12 +466,12 @@
 
         // Changing non-opportunistic sub1 shouldn't trigger callback.
         mSubscriptionControllerUT.setDisplayNameUsingSrc("DisplayName", 1,
-                SubscriptionManager.NAME_SOURCE_SIM_SOURCE);
+                SubscriptionManager.NAME_SOURCE_SIM_SPN);
         verify(mTelephonyRegisteryMock, times(1))
                 .notifyOpportunisticSubscriptionInfoChanged();
 
         mSubscriptionControllerUT.setDisplayNameUsingSrc("DisplayName", 2,
-                SubscriptionManager.NAME_SOURCE_SIM_SOURCE);
+                SubscriptionManager.NAME_SOURCE_SIM_SPN);
         verify(mTelephonyRegisteryMock, times(2))
                 .notifyOpportunisticSubscriptionInfoChanged();
     }
@@ -729,6 +730,57 @@
 
     @Test
     @SmallTest
+    public void testAddSubscriptionIntoGroupWithCarrierPrivilegePermission() throws Exception {
+        testInsertSim();
+        // Adding a second profile and mark as embedded.
+        // TODO b/123300875 slot index 1 is not expected to be valid
+        mSubscriptionControllerUT.addSubInfoRecord("test2", 1);
+        ContentValues values = new ContentValues();
+        values.put(SubscriptionManager.IS_EMBEDDED, 1);
+        mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
+                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null);
+        mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();
+
+        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE);
+
+        // Create group for sub 1.
+        int[] subIdList = new int[] {1};
+        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
+        ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup(
+                subIdList, "packageName1");
+
+        // Try to add sub 2 into group of sub 1.
+        // Should fail as it doesn't have carrier privilege on sub 2.
+        try {
+            mSubscriptionControllerUT.addSubscriptionsIntoGroup(
+                    new int[] {2}, groupId, "packageName1");
+            fail("addSubscriptionsIntoGroup should fail with no permission on sub 2.");
+        } catch (SecurityException e) {
+            // Expected result.
+        }
+
+        doReturn(false).when(mTelephonyManager).hasCarrierPrivileges(1);
+        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2);
+        // Try to add sub 2 into group of sub 1.
+        // Should fail as it doesn't have carrier privilege on sub 1.
+        try {
+            mSubscriptionControllerUT.addSubscriptionsIntoGroup(
+                    new int[] {2}, groupId, "packageName2");
+            fail("addSubscriptionsIntoGroup should fail with no permission on the group (sub 1).");
+        } catch (SecurityException e) {
+            // Expected result.
+        }
+
+        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
+        mSubscriptionControllerUT.addSubscriptionsIntoGroup(new int[] {2}, groupId, "packageName2");
+        List<SubscriptionInfo> infoList = mSubscriptionControllerUT
+                .getSubscriptionsInGroup(groupId, "packageName2");
+        assertEquals(2, infoList.size());
+    }
+
+    @Test
+    @SmallTest
     public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
         testInsertSim();
         // Adding a second profile and mark as embedded.
@@ -893,6 +945,15 @@
                 .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
         assertEquals(1, infoList.size());
         assertEquals(2, infoList.get(0).getSubscriptionId());
+
+        // Adding sub 1 into a non-existing UUID, which should be granted.
+        groupUuid = new ParcelUuid(UUID.randomUUID());
+        mSubscriptionControllerUT.addSubscriptionsIntoGroup(
+                subIdList, groupUuid, mContext.getOpPackageName());
+        infoList = mSubscriptionControllerUT
+                .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
+        assertEquals(1, infoList.size());
+        assertEquals(1, infoList.get(0).getSubscriptionId());
     }
 
     private void registerMockTelephonyRegistry() {
@@ -1004,4 +1065,28 @@
         mSubscriptionControllerUT.setAlwaysAllowMmsData(0, false);
         verify(mDataEnabledSettings).setAlwaysAllowMmsData(eq(false));
     }
+
+    @Test
+    @SmallTest
+    public void testNameSourcePriority() throws Exception {
+        assertTrue(mSubscriptionControllerUT.getNameSourcePriority(
+                SubscriptionManager.NAME_SOURCE_USER_INPUT)
+                > mSubscriptionControllerUT.getNameSourcePriority(
+                        SubscriptionManager.NAME_SOURCE_CARRIER));
+
+        assertTrue(mSubscriptionControllerUT.getNameSourcePriority(
+                SubscriptionManager.NAME_SOURCE_CARRIER)
+                > mSubscriptionControllerUT.getNameSourcePriority(
+                SubscriptionManager.NAME_SOURCE_SIM_SPN));
+
+        assertTrue(mSubscriptionControllerUT.getNameSourcePriority(
+                SubscriptionManager.NAME_SOURCE_SIM_SPN)
+                > mSubscriptionControllerUT.getNameSourcePriority(
+                SubscriptionManager.NAME_SOURCE_SIM_PNN));
+
+        assertTrue(mSubscriptionControllerUT.getNameSourcePriority(
+                SubscriptionManager.NAME_SOURCE_SIM_PNN)
+                > mSubscriptionControllerUT.getNameSourcePriority(
+                SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
index 977b45a..de7d12a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
@@ -359,6 +359,7 @@
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone));
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone));
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone));
+        assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone));
 
         // Carrier config settings changes.
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
@@ -404,6 +405,7 @@
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone));
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone));
         assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone));
+        assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone));
     }
 
     @Test
@@ -434,6 +436,7 @@
                 createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_IMS), mPhone));
 
         assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone));
+        assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_XCAP), mPhone));
     }
 
     @Test
@@ -472,6 +475,7 @@
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone));
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone));
         assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone));
+        assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone));
     }
 
     @Test
@@ -552,7 +556,7 @@
                 ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_IA)
                 .canHandleType(ApnSetting.TYPE_IA));
 
-        // same for emergency and mcx
+        // same for emergency, mcx, and xcap
         assertFalse(createApnSetting(ApnSetting.TYPE_ALL)
                 .canHandleType(ApnSetting.TYPE_EMERGENCY));
         assertTrue(createApnSetting(
@@ -563,6 +567,11 @@
         assertTrue(createApnSetting(
                 ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_MCX)
                 .canHandleType(ApnSetting.TYPE_MCX));
+        assertFalse(createApnSetting(ApnSetting.TYPE_ALL)
+                .canHandleType(ApnSetting.TYPE_XCAP));
+        assertTrue(createApnSetting(
+                ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP)
+                .canHandleType(ApnSetting.TYPE_XCAP));
 
         // check carrier disabled
         assertFalse(createDisabledApnSetting(ApnSetting.TYPE_ALL)
@@ -578,6 +587,9 @@
         assertFalse(createDisabledApnSetting(
                 ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_IA)
                 .canHandleType(ApnSetting.TYPE_IA));
+        assertFalse(createDisabledApnSetting(
+                ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP)
+                .canHandleType(ApnSetting.TYPE_XCAP));
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index f6ef326..1cd8bd4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -108,7 +108,8 @@
             "mobile_supl,3,0,2,60000,true", "mobile_dun,4,0,2,60000,true",
             "mobile_hipri,5,0,3,60000,true", "mobile_fota,10,0,2,60000,true",
             "mobile_ims,11,0,2,60000,true", "mobile_cbs,12,0,2,60000,true",
-            "mobile_ia,14,0,2,-1,true", "mobile_emergency,15,0,2,-1,true"};
+            "mobile_ia,14,0,2,-1,true", "mobile_emergency,15,0,2,-1,true",
+            "mobile_xcap,18,0,2,-1,true"};
 
     public static final String FAKE_APN1 = "FAKE APN 1";
     public static final String FAKE_APN2 = "FAKE APN 2";
@@ -1072,9 +1073,26 @@
         waitForMs(200);
 
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
-                eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
+                eq(DataService.REQUEST_REASON_NORMAL), any(), any(Message.class));
+    }
+
+    // Test the XCAP APN setup.
+    @Test
+    @SmallTest
+    public void testTrySetupDataXcapApn() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_XCAP, new String[]{PhoneConstants.APN_TYPE_ALL});
+
+        logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+        waitForMs(200);
+
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+                eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
+                eq(DataService.REQUEST_REASON_NORMAL), any(), any(Message.class));
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
index 9250942..ad6e7ec 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.net.NetworkCapabilities;
@@ -57,6 +58,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -72,6 +74,9 @@
     @Mock
     private RadioConfig mMockRadioConfig;
 
+    @Mock
+    private DataConnection mDataConnection;
+
     private String mTestName = "";
 
     private final ArrayList<NetworkRequest> mNetworkRequestList = new ArrayList<>();
@@ -346,4 +351,41 @@
         h.sendMessage(h.obtainMessage(5, ar));
         processAllMessages();
     }
+
+    /**
+     * Test handover when the data connection is being connected.
+     */
+    @Test
+    @SmallTest
+    public void testHandoverActivatingData() throws Exception {
+        createMockedTelephonyComponents();
+        doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0);
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
+                TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
+
+        activatePhoneInPhoneSwitcher(0, true);
+        makeDefaultInternetRequest();
+
+        makeSubSpecificMmsRequest(0);
+        processAllMessages();
+
+        Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler");
+        f.setAccessible(true);
+        Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT);
+
+        HandoverCallback handoverCallback = mock(HandoverCallback.class);
+        Mockito.reset(mDcTracker);
+        doReturn(mDataConnection).when(mDcTracker).getDataConnectionByApnType(anyString());
+        doReturn(false).when(mDataConnection).isActive();
+
+        HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback);
+        AsyncResult ar = new AsyncResult(null, hp, null);
+        h.sendMessage(h.obtainMessage(5, ar));
+        processAllMessages();
+
+        verify(mDcTracker, times(1)).releaseNetwork(any(), eq(1));
+        verify(mDcTracker, times(1)).requestNetwork(any(), eq(1), any());
+    }
+
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
index 3b23510..2dce712 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.nullable;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
@@ -806,8 +807,9 @@
         SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
 
         // verify that a broadcast receiver is registered for current user (user == null) based on
-        // implementation in ContextFixture
-        verify(mContext, times(1)).registerReceiverAsUser(any(BroadcastReceiver.class),
+        // implementation in ContextFixture. registerReceiver may be called more than once (for
+        // example by GsmInboundSmsHandler if TEST_MODE is true)
+        verify(mContext, atLeastOnce()).registerReceiverAsUser(any(BroadcastReceiver.class),
                 eq((UserHandle)null), any(IntentFilter.class), eq((String)null), eq((Handler)null));
 
         // wait for ScanRawTableThread
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/CallQualityMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/CallQualityMetricsTest.java
index 0fe4fc1..e1be031 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/CallQualityMetricsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/CallQualityMetricsTest.java
@@ -27,7 +27,6 @@
 import android.telephony.CellSignalStrengthTdscdma;
 import android.telephony.CellSignalStrengthWcdma;
 import android.telephony.SignalStrength;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.CallQualitySummary;
@@ -68,7 +67,6 @@
      * Verify that good/bad quality and total duration stats are correct.
      */
     @Test
-    @SmallTest
     public void testTotalDurations() {
         // Call quality in the following sequence:
         //
@@ -106,11 +104,108 @@
     }
 
     /**
+     * Verify that good/bad quality and total duration stats are correct.
+     *
+     * Similar to testTotalDurations, but getCallQualitySummaryUl/Dl will be called multiple times,
+     * so verify that it continues to work after the first call.
+     */
+    @Test
+    public void testTotalDurations_MultipleChecks() {
+        // Call quality in the following sequence:
+        //
+        // DL: GOOD       GOOD      BAD
+        // UL: GOOD       BAD       GOOD
+        // |----------|----------|--------|
+        // 0          5          10       14
+        //
+        // 0s = Start of call. Assumed to be good quality
+        // 5s = Switches to UL bad quality
+        // 10s = Switches to UL good quality, DL bad quality
+        // 14s = End of call. Switches to UL bad quality, DL good quality
+        CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
+                CallQuality.CALL_QUALITY_BAD, 5000);
+        CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
+                CallQuality.CALL_QUALITY_EXCELLENT, 10000);
+        CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
+                CallQuality.CALL_QUALITY_BAD, 14000);
+
+        mCallQualityMetrics.saveCallQuality(cq1);
+        mCallQualityMetrics.saveCallQuality(cq2);
+        mCallQualityMetrics.saveCallQuality(cq3);
+
+        // verify UL quality durations
+        CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
+        assertEquals(9, dlSummary.totalGoodQualityDurationInSeconds);
+        assertEquals(5, dlSummary.totalBadQualityDurationInSeconds);
+        assertEquals(14, dlSummary.totalDurationWithQualityInformationInSeconds);
+
+        // verify DL quality durations
+        CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
+        assertEquals(5, ulSummary.totalGoodQualityDurationInSeconds);
+        assertEquals(9, ulSummary.totalBadQualityDurationInSeconds);
+        assertEquals(14, ulSummary.totalDurationWithQualityInformationInSeconds);
+
+        // verify UL quality durations
+        dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
+        assertEquals(9, dlSummary.totalGoodQualityDurationInSeconds);
+        assertEquals(5, dlSummary.totalBadQualityDurationInSeconds);
+        assertEquals(14, dlSummary.totalDurationWithQualityInformationInSeconds);
+
+        // verify DL quality durations
+        ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
+        assertEquals(5, ulSummary.totalGoodQualityDurationInSeconds);
+        assertEquals(9, ulSummary.totalBadQualityDurationInSeconds);
+        assertEquals(14, ulSummary.totalDurationWithQualityInformationInSeconds);
+    }
+
+
+    /**
+     * Verify that good/bad quality and total duration stats are correct.
+     *
+     * Similar to testTotalDurations but we report the call quality out of order.
+     */
+    @Test
+    public void testTotalDurations_ReportedOutOfOrder() {
+        // Call quality in the following sequence:
+        //
+        // DL: GOOD       GOOD      BAD
+        // UL: GOOD       BAD       GOOD
+        // |----------|----------|--------|
+        // 0          5          10       14
+        //
+        // 0s = Start of call. Assumed to be good quality
+        // 5s = Switches to UL bad quality
+        // 10s = Switches to UL good quality, DL bad quality
+        // 14s = End of call. Switches to UL bad quality, DL good quality
+        CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
+                CallQuality.CALL_QUALITY_BAD, 5000);
+        CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
+                CallQuality.CALL_QUALITY_EXCELLENT, 10000);
+        CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
+                CallQuality.CALL_QUALITY_BAD, 14000);
+
+        mCallQualityMetrics.saveCallQuality(cq1);
+        mCallQualityMetrics.saveCallQuality(cq3);
+        mCallQualityMetrics.saveCallQuality(cq2);
+
+        // verify UL quality durations
+        CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
+        assertEquals(9, dlSummary.totalGoodQualityDurationInSeconds);
+        assertEquals(5, dlSummary.totalBadQualityDurationInSeconds);
+        assertEquals(14, dlSummary.totalDurationWithQualityInformationInSeconds);
+
+        // verify DL quality durations
+        CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
+        assertEquals(5, ulSummary.totalGoodQualityDurationInSeconds);
+        assertEquals(9, ulSummary.totalBadQualityDurationInSeconds);
+        assertEquals(14, ulSummary.totalDurationWithQualityInformationInSeconds);
+    }
+
+    /**
      * Verify that a new CallQualityMetrics object is able to return empty summaries if no
      * CallQuality is reported for the duration of a call.
      */
     @Test
-    @SmallTest
     public void testNoQualityReported() {
         // getting the summary for a new CallQualityMetrics object should not fail, and all
         // durations should be 0
@@ -129,7 +224,6 @@
      * ignored.
      */
     @Test
-    @SmallTest
     public void testNotAvailableIsIgnored() {
         // CallQuality updates from the IMS service with CALL_QUALITY_NOT_AVAILABLE should be
         // ignored
@@ -156,7 +250,6 @@
      * this just tests for good quality since the logic is the same.
      */
     @Test
-    @SmallTest
     public void testBestAndWorstSs() {
         // save good quality with high rssnr
         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
@@ -201,7 +294,6 @@
      * likely that one field would be preserved and others would be lost.
      */
     @Test
-    @SmallTest
     public void testSnapshotOfEndDuration() {
         CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
                 CallQuality.CALL_QUALITY_BAD, 5000);
@@ -220,4 +312,31 @@
         CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
         assertEquals(14, ulSummary.snapshotOfEnd.durationInSeconds);
     }
+
+    /**
+     * Verifies that the snapshot of the end (the last reported call quality) is correct.
+     * Currently this just checks the duration since the logic is all the same and it doesn't seem
+     * likely that one field would be preserved and others would be lost.
+     *
+     * Similar to testSnapshotOfEndDuration but we report the call quality out of order
+     */
+    @Test
+    public void testSnapshotOfEndDuration_ReportedOutOfOrder() {
+        CallQuality cq1 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
+                CallQuality.CALL_QUALITY_BAD, 5000);
+        CallQuality cq2 = constructCallQuality(CallQuality.CALL_QUALITY_BAD,
+                CallQuality.CALL_QUALITY_EXCELLENT, 10000);
+        CallQuality cq3 = constructCallQuality(CallQuality.CALL_QUALITY_EXCELLENT,
+                CallQuality.CALL_QUALITY_BAD, 14000);
+
+        mCallQualityMetrics.saveCallQuality(cq1);
+        mCallQualityMetrics.saveCallQuality(cq3);
+        mCallQualityMetrics.saveCallQuality(cq2);
+
+        // verify snapshot of end
+        CallQualitySummary dlSummary = mCallQualityMetrics.getCallQualitySummaryDl();
+        assertEquals(14, dlSummary.snapshotOfEnd.durationInSeconds);
+        CallQualitySummary ulSummary = mCallQualityMetrics.getCallQualitySummaryUl();
+        assertEquals(14, ulSummary.snapshotOfEnd.durationInSeconds);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
index 46001c7..30e1297 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony.metrics;
 
+import static android.telephony.NetworkRegistrationInfo.NR_STATE_NONE;
+import static android.telephony.ServiceState.FREQUENCY_RANGE_UNKNOWN;
 import static android.telephony.ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
 import static android.telephony.ServiceState.ROAMING_TYPE_DOMESTIC;
 
@@ -36,6 +38,7 @@
 import static org.mockito.Mockito.doReturn;
 
 import android.net.LinkAddress;
+import android.net.NetworkCapabilities;
 import android.net.NetworkUtils;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -67,6 +70,8 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyLog;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState.FrequencyRange;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState.NrState;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState.RoamingType;
 
 import org.junit.After;
@@ -108,14 +113,13 @@
 
         doReturn(ROAMING_TYPE_DOMESTIC).when(mServiceState).getVoiceRoamingType();
         doReturn(ROAMING_TYPE_DOMESTIC).when(mServiceState).getDataRoamingType();
-        doReturn("voiceshort").when(mServiceState).getVoiceOperatorAlphaShort();
-        doReturn("voicelong").when(mServiceState).getVoiceOperatorAlphaLong();
-        doReturn("datashort").when(mServiceState).getDataOperatorAlphaShort();
-        doReturn("datalong").when(mServiceState).getDataOperatorAlphaLong();
-        doReturn("123456").when(mServiceState).getVoiceOperatorNumeric();
-        doReturn("123456").when(mServiceState).getDataOperatorNumeric();
+        doReturn("short").when(mServiceState).getOperatorAlphaShort();
+        doReturn("long").when(mServiceState).getOperatorAlphaLong();
+        doReturn("123456").when(mServiceState).getOperatorNumeric();
         doReturn(RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState).getRilVoiceRadioTechnology();
         doReturn(RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState).getRilDataRadioTechnology();
+        doReturn(FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange();
+        doReturn(NR_STATE_NONE).when(mServiceState).getNrState();
     }
 
     @After
@@ -300,6 +304,32 @@
                 log.events[0].updatedEmergencyNumber.routing);
     }
 
+    // Test write Network Capabilities changed event
+    @Test
+    @SmallTest
+    public void testWriteNetworkCapabilitiesChangedEvent() throws Exception {
+        NetworkCapabilities caps = new NetworkCapabilities();
+        caps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        mMetrics.writeNetworkCapabilitiesChangedEvent(mPhone.getPhoneId(), caps);
+
+        caps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        mMetrics.writeNetworkCapabilitiesChangedEvent(mPhone.getPhoneId(), caps);
+
+        TelephonyLog log = buildProto();
+
+        assertEquals(2, log.events.length);
+        assertEquals(0, log.callSessions.length);
+        assertEquals(0, log.smsSessions.length);
+
+        assertEquals(mPhone.getPhoneId(), log.events[0].phoneId);
+        assertEquals(TelephonyEvent.Type.NETWORK_CAPABILITIES_CHANGED, log.events[0].type);
+        assertTrue(log.events[0].networkCapabilities.isNetworkUnmetered);
+
+        assertEquals(mPhone.getPhoneId(), log.events[1].phoneId);
+        assertEquals(TelephonyEvent.Type.NETWORK_CAPABILITIES_CHANGED, log.events[1].type);
+        assertFalse(log.events[1].networkCapabilities.isNetworkUnmetered);
+    }
+
     // Test write on IMS call start
     @Test
     @SmallTest
@@ -675,17 +705,21 @@
 
         assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.dataRoamingType);
 
-        assertEquals("voicelong", state.voiceOperator.alphaLong);
+        assertEquals("long", state.voiceOperator.alphaLong);
 
-        assertEquals("voiceshort", state.voiceOperator.alphaShort);
+        assertEquals("short", state.voiceOperator.alphaShort);
 
         assertEquals("123456", state.voiceOperator.numeric);
 
-        assertEquals("datalong", state.dataOperator.alphaLong);
+        assertEquals("long", state.dataOperator.alphaLong);
 
-        assertEquals("datashort", state.dataOperator.alphaShort);
+        assertEquals("short", state.dataOperator.alphaShort);
 
         assertEquals("123456", state.dataOperator.numeric);
+
+        assertEquals(FrequencyRange.FREQUENCY_RANGE_UNKNOWN, state.nrFrequencyRange);
+
+        assertEquals(NrState.NR_STATE_NONE, state.nrState);
     }
 
     // Test reset scenario
@@ -719,15 +753,15 @@
 
         assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.dataRoamingType);
 
-        assertEquals("voicelong", state.voiceOperator.alphaLong);
+        assertEquals("long", state.voiceOperator.alphaLong);
 
-        assertEquals("voiceshort", state.voiceOperator.alphaShort);
+        assertEquals("short", state.voiceOperator.alphaShort);
 
         assertEquals("123456", state.voiceOperator.numeric);
 
-        assertEquals("datalong", state.dataOperator.alphaLong);
+        assertEquals("long", state.dataOperator.alphaLong);
 
-        assertEquals("datashort", state.dataOperator.alphaShort);
+        assertEquals("short", state.dataOperator.alphaShort);
 
         assertEquals("123456", state.dataOperator.numeric);
     }