Merge "Call mLoaded.set(false) for fileupdate default case"
diff --git a/Android.bp b/Android.bp
index 8cf8d0d..693da7c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -36,39 +36,22 @@
     path: "src/java",
 }
 
-java_library {
-    name: "telephony-common",
+filegroup {
+    name: "jarjar-rules-shared",
+    srcs: ["jarjar-rules-shared.txt"],
+}
+
+android_app {
+    name: "telephony-resources",
     installable: true,
 
-    aidl: {
-        local_include_dirs: ["src/java"],
-    },
-    srcs: [
-        ":opt-telephony-common-srcs",
-        "src/java/**/I*.aidl",
-        "src/java/**/*.logtags",
+    resource_dirs: [
+        "res",
     ],
 
-    jarjar_rules: ":framework-jarjar-rules",
-
-    libs: [
-        "android.hardware.radio-V1.0-java",
-        "android.hardware.radio-V1.1-java",
-        "android.hardware.radio-V1.2-java",
-        "android.hardware.radio-V1.3-java",
-        "android.hardware.radio-V1.4-java",
-        "voip-common",
-        "ims-common",
-        "services",
-    ],
-    static_libs: [
-        "android.hardware.radio.config-V1.0-java-shallow",
-        "android.hardware.radio.config-V1.1-java-shallow",
-        "android.hardware.radio.config-V1.2-java-shallow",
-        "android.hardware.radio.deprecated-V1.0-java-shallow",
-        "telephony-protos",
-        "ecc-protos-lite",
-    ],
+    platform_apis: true,
+    manifest: "AndroidManifest_Resources.xml",
+    export_package_resources: true,
 
     product_variables: {
         pdk: {
@@ -78,3 +61,52 @@
     },
 }
 
+java_library {
+    name: "telephony-common",
+    installable: true,
+
+    aidl: {
+        local_include_dirs: ["src/java"],
+    },
+    srcs: [
+        ":opt-telephony-common-srcs",
+        ":framework-telephony-stack-shared-srcs",
+        "src/java/**/I*.aidl",
+        "src/java/**/*.logtags",
+    ],
+
+    jarjar_rules: ":jarjar-rules-shared",
+
+    libs: [
+        "android.hardware.radio-V1.0-java",
+        "android.hardware.radio-V1.1-java",
+        "android.hardware.radio-V1.2-java",
+        "android.hardware.radio-V1.3-java",
+        "android.hardware.radio-V1.4-java",
+        "android.hardware.radio-V1.5-java",
+        "voip-common",
+        "ims-common",
+        "services",
+        "unsupportedappusage",
+        "telephony-resources",
+    ],
+    required: ["telephony-resources"],
+    static_libs: [
+        "android.hardware.radio.config-V1.0-java-shallow",
+        "android.hardware.radio.config-V1.1-java-shallow",
+        "android.hardware.radio.config-V1.2-java-shallow",
+        "android.hardware.radio.config-V1.3-java-shallow",
+        "android.hardware.radio.deprecated-V1.0-java-shallow",
+        "ecc-protos-lite",
+        "libphonenumber-nogeocoder",
+        "PlatformProperties",
+        "telephony-protos",
+    ],
+
+    product_variables: {
+        pdk: {
+            // enable this build only when platform library is available
+            enabled: false,
+        },
+    },
+}
diff --git a/AndroidManifest_Resources.xml b/AndroidManifest_Resources.xml
new file mode 100644
index 0000000..7afba27
--- /dev/null
+++ b/AndroidManifest_Resources.xml
@@ -0,0 +1,8 @@
+<!-- Manifest for telephony resources APK -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.telephony.resources">
+    <application
+        android:directBootAware="true"
+        android:hasCode="false">
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/OWNERS b/OWNERS
index 8f494b2..0f8fc34 100644
--- a/OWNERS
+++ b/OWNERS
@@ -11,4 +11,5 @@
 refuhoo@google.com
 paulye@google.com
 nazaninb@google.com
-sarahchin@google.com
\ No newline at end of file
+sarahchin@google.com
+dbright@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..e75dcb0
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "TeleServiceTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/jarjar-rules-shared.txt b/jarjar-rules-shared.txt
new file mode 100644
index 0000000..aa887da
--- /dev/null
+++ b/jarjar-rules-shared.txt
@@ -0,0 +1,19 @@
+rule android.os.RegistrantList* com.android.internal.telephony.RegistrantList@1
+rule android.os.Registrant* com.android.internal.telephony.Registrant@1
+rule android.hidl.** android.internal.hidl.@1
+rule android.sysprop.** android.internal.telephony.sysprop.@1
+rule android.util.LocalLog* com.android.internal.telephony.LocalLog@1
+rule android.util.TimeUtils* com.android.internal.telephony.TimeUtils@1
+rule com.android.internal.os.SomeArgs* com.android.internal.telephony.SomeArgs@1
+rule com.android.internal.util.AsyncChannel* com.android.internal.telephony.AsyncChannel@1
+rule com.android.internal.util.AsyncService* com.android.internal.telephony.AsyncService@1
+rule com.android.internal.util.BitwiseInputStream* com.android.internal.telephony.BitwiseInputStream@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.IState* com.android.internal.telephony.IState@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.UserIcons* com.android.internal.telephony.UserIcons@1
+rule com.google.i18n.phonenumbers.** com.android.internal.telephony.phonenumbers.@1
diff --git a/proto/Android.bp b/proto/Android.bp
index 166be3d..d7e379f 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -22,8 +22,8 @@
         ],
     },
     srcs: ["src/**/*.proto"],
-    sdk_version: "core_platform",
+    sdk_version: "system_current",
     jarjar_rules: "jarjar-rules.txt",
     // Pin java_version until jarjar is certified to support later versions. http://b/72703434
     java_version: "1.8",
-}
\ No newline at end of file
+}
diff --git a/proto/src/carrierId.proto b/proto/src/carrierId.proto
deleted file mode 100644
index 0f5eba8..0000000
--- a/proto/src/carrierId.proto
+++ /dev/null
@@ -1,92 +0,0 @@
-//
-// Copyright (C) 2017 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.
-//
-
-syntax = "proto2";
-
-package carrierIdentification;
-
-option java_package = "com.android.internal.telephony";
-option java_outer_classname = "CarrierIdProto";
-
-// A complete list of carriers
-message CarrierList {
-  // A collection of carriers. one entry for one carrier.
-  repeated CarrierId carrier_id = 1;
-  // Version number of current carrier list
-  optional int32 version = 2;
-};
-
-// CarrierId is the unique representation of a carrier in CID table.
-message CarrierId {
-  // [Optional] A unique canonical number designated to a carrier.
-  optional int32 canonical_id = 1;
-
-  // [Optional] A user-friendly carrier name (not localized).
-  optional string carrier_name = 2;
-
-  // [Optional] Carrier attributes to match a carrier. At least one value is required.
-  repeated CarrierAttribute carrier_attribute = 3;
-
-  // [Optional] A unique canonical number to represent its parent carrier. The parent-child
-  // relationship can be used to differentiate a single carrier by different networks,
-  // by prepaid v.s. postpaid  or even by 4G v.s. 3G plan.
-  optional int32 parent_canonical_id = 4;
-};
-
-// Attributes used to match a carrier.
-// For each field within this message:
-//   - if not set, the attribute is ignored;
-//   - if set, the device must have one of the specified values to match.
-// Match is based on AND between any field that is set and OR for values within a repeated field.
-message CarrierAttribute {
-  // [Optional] The MCC and MNC that map to this carrier. At least one value is required.
-  repeated string mccmnc_tuple = 1;
-
-  // [Optional] Prefix of IMSI (International Mobile Subscriber Identity) in
-  // decimal format. Some digits can be replaced with "x" symbols matching any digit.
-  // Sample values: 20404794, 21670xx2xxx.
-  repeated string imsi_prefix_xpattern = 2;
-
-  // [Optional] The Service Provider Name. Read from subscription EF_SPN.
-  // Sample values: C Spire, LeclercMobile
-  repeated string spn = 3;
-
-  // [Optional] PLMN network name. Read from subscription EF_PNN.
-  // Sample values:
-  repeated string plmn = 4;
-
-  // [Optional] Group Identifier Level1 for a GSM phone. Read from subscription EF_GID1.
-  // Sample values: 6D, BAE0000000000000
-  repeated string gid1 = 5;
-
-  // [Optional] Group Identifier Level2 for a GSM phone. Read from subscription EF_GID2.
-  // Sample values: 6D, BAE0000000000000
-  repeated string gid2 = 6;
-
-  // [Optional] The Access Point Name, corresponding to "apn" field returned by
-  // "content://telephony/carriers/preferapn" on device.
-  // Sample values: fast.t-mobile.com, internet
-  repeated string preferred_apn = 7;
-
-  // [Optional] Prefix of Integrated Circuit Card Identifier. Read from subscription EF_ICCID.
-  // Sample values: 894430, 894410
-  repeated string iccid_prefix = 8;
-
-  // [Optional] Carrier Privilege Access Rule in hex string.
-  // Sample values: 61ed377e85d386a8dfee6b864bd85b0bfaa5af88
-  repeated string privilege_access_rule = 9;
-};
-
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index ec2acf4..020aba6 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
@@ -720,7 +766,7 @@
     // along with the event if it is available
     MODEM_RESTART = 11;
 
-    // System time overwritten by NITZ (Network time)
+    // A system time update suggestion was made from a received NITZ (Network time) signal
     NITZ_TIME = 12;
 
     // Carrier Identification Matching Event
@@ -749,6 +795,12 @@
 
     // Emergency Number update event (Device HAL >= 1.4).
     EMERGENCY_NUMBER_REPORT = 21;
+
+    // Network capabilities change event.
+    NETWORK_CAPABILITIES_CHANGED = 22;
+
+    // Signal strength
+    SIGNAL_STRENGTH = 23;
   }
 
   enum ApnType {
@@ -1651,6 +1703,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;
 
@@ -1693,7 +1750,7 @@
   // Modem restart event
   optional ModemRestart modem_restart = 14;
 
-  // NITZ time in milliseconds
+  // NITZ time in milliseconds (see TelephonyEvent.Type.NITZ_TIME)
   optional int64 nitz_timestamp_millis = 15;
 
   // Carrier id matching event
@@ -1723,6 +1780,19 @@
 
   // Updated Emergency Call info.
   optional EmergencyNumberInfo updated_emergency_number = 25;
+
+  // NetworkCapabilities changed info.
+  optional NetworkCapabilitiesInfo network_capabilities = 26;
+
+  // Signal strength
+  optional int32 signal_strength = 27;
+
+  // Indicate the version of emergency number database in Android platform
+  optional int32 emergency_number_database_version = 28;
+  // [
+  //  (datapol.semantic_type) = ST_SOFTWARE_ID,
+  //  (datapol.qualifier) = { is_public: true }
+  //]
 }
 
 message ActiveSubscriptionInfo {
@@ -2032,6 +2102,13 @@
 
       // Indicate the emergency call information dialed from the CS call
       optional EmergencyNumberInfo emergency_number_info = 8;
+
+      // Indicate the version of emergency number database in Android platform
+      optional int32 emergency_number_database_version = 9;
+      // [
+      //  (datapol.semantic_type) = ST_SOFTWARE_ID,
+      //  (datapol.qualifier) = { is_public: true }
+      //]
     }
 
     // Single Radio Voice Call Continuity(SRVCC) progress state
@@ -2128,6 +2205,18 @@
 
       // the codec type of an ongoing call
       optional AudioCodec codec_type = 11;
+
+      // true if no incoming RTP is received for a continuous duration of 4 seconds
+      optional bool rtp_inactivity_detected = 12;
+
+      // true if only silence RTP packets are received for 20 seconds immediately
+      // after call is connected
+      optional bool rx_silence_detected = 13;
+
+      // true if only silence RTP packets are sent for 20 seconds immediately
+      // after call is connected
+      optional bool tx_silence_detected = 14;
+
     }
 
     message CallQualitySummary {
@@ -2258,6 +2347,13 @@
 
     // Emergency call info
     optional EmergencyNumberInfo ims_emergency_number_info = 27;
+
+    // Indicate the version of emergency number database in Android platform
+    optional int32 emergency_number_database_version = 28;
+    // [
+    //  (datapol.semantic_type) = ST_SOFTWARE_ID,
+    //  (datapol.qualifier) = { is_public: true }
+    //]
   }
 
   // Time when call has started, in minutes since epoch,
diff --git a/res/values/config.xml b/res/values/config.xml
new file mode 100644
index 0000000..5ea773e
--- /dev/null
+++ b/res/values/config.xml
@@ -0,0 +1,298 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2020, 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds.  Do not translate.
+
+     NOTE: The naming convention is "config_camelCaseValue". Some legacy
+     entries do not follow the convention, but all new entries should. -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- The RadioAccessFamilies supported by the device.
+         Empty is viewed as "all".  Only used on devices which
+         don't support RIL_REQUEST_GET_RADIO_CAPABILITY
+         format is UMTS|LTE|... -->
+    <string translatable="false" name="config_radio_access_family"></string>
+
+    <!-- MMS user agent string -->
+    <string name="config_mms_user_agent" translatable="false"></string>
+
+    <!-- MMS user agent prolfile url -->
+    <string name="config_mms_user_agent_profile_url" translatable="false"></string>
+
+    <!-- Config determines whether to update phone object when voice registration
+         state changes. Voice radio tech change will always trigger an update of
+         phone object irrespective of this config -->
+    <bool name="config_switch_phone_on_voice_reg_state_change">true</bool>
+
+    <!-- Boolean indicating if restoring network selection should be skipped -->
+    <!-- The restoring is handled by modem if it is true-->
+    <bool translatable="false" name="skip_restoring_network_selection">false</bool>
+
+    <!-- An array of CDMA roaming indicators which means international roaming -->
+    <integer-array translatable="false" name="config_cdma_international_roaming_indicators" />
+
+    <!-- Configure mobile network MTU. The standard default is set here but each carrier
+         may have a specific value set in an overlay config.xml file. -->
+    <integer name="config_mobile_mtu">1500</integer>
+
+    <!-- Configure mobile tcp buffer sizes in the form:
+         rat-name:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
+         If no value is found for the rat-name in use, the system default will be applied.
+    -->
+    <string-array name="config_mobile_tcp_buffers">
+    </string-array>
+
+    <!-- flag to indicate if EF LI/EF PL should be used for system language -->
+    <bool name="config_use_sim_language_file">false</bool>
+
+    <!-- List of countries in which we display 'No service' on status bar
+         instead of 'Emergency calls only' when SIM is unready. -->
+    <string-array translatable="false" name="config_display_no_service_when_sim_unready">
+        <item>"DE"</item>
+        <item>"GB"</item>
+        <item>"JP"</item>
+    </string-array>
+
+    <!-- Flag indicating whether the surface flinger is inefficient
+         at performing a blur.  Used by parts of the UI to turn off
+         the blur effect where it isn't worth the performance hit.
+         As of Honeycomb, blurring is not supported anymore. -->
+    <bool name="config_sf_slowBlur">true</bool>
+
+    <!-- set to false if we need to show user confirmation
+         when alpha identifier is not provided by the UICC -->
+    <bool name="config_stkNoAlphaUsrCnf">true</bool>
+
+    <!-- Number of physical SIM slots on the device. This includes both eSIM and pSIM slots, and
+         is not necessarily the same as the number of phones/logical modems supported by the device.
+         For example, a multi-sim device can have 2 phones/logical modems, but 3 physical slots,
+         or a single SIM device can have 1 phones/logical modems, but 2 physical slots (one eSIM
+         and one pSIM) -->
+    <integer name="config_num_physical_slots">1</integer>
+
+    <!-- Is the device capable of hot swapping an UICC Card -->
+    <bool name="config_hotswapCapable">false</bool>
+
+    <!-- An array of device capabilities defined by GSMA SGP.22 v2.0.
+         The first item is the capability name that the device supports. The second item is the
+         major version. The minor and revision versions are default to 0s.
+         The device capabilities and their definition in the spec are:
+             gsm : gsmSupportedRelease
+             utran : utranSupportedRelease
+             cdma1x : cdma2000onexSupportedRelease
+             hrpd : cdma2000hrpdSupportedRelease
+             ehrpd : cdma2000ehrpdSupportedRelease
+             eutran : eutranSupportedRelease
+             nfc : contactlessSupportedRelease
+             crl : rspCrlSupportedVersion
+    -->
+    <string-array translatable="false" name="config_telephonyEuiccDeviceCapabilities">
+        <!-- Example:
+        <item>"gsm,11"</item>
+        <item>"utran,11"</item>
+        <item>"cdma1x,1"</item>
+        <item>"hrpd,3"</item>
+        <item>"ehrpd,12"</item>
+        <item>"eutran,11"</item>
+        <item>"nfc,1"</item>
+        <item>"crl,1"</item>
+        -->
+    </string-array>
+
+    <!-- If this value is true, duplicate Source/Destination port fields
+         in WDP header of some carriers OMADM wap push are supported.
+         ex: MSGTYPE-TotalSegments-CurrentSegment
+             -SourcePortDestPort-SourcePortDestPort-OMADM PDU
+         If false, not supported. -->
+    <bool name="config_duplicate_port_omadm_wappush">false</bool>
+
+    <!-- Cellular network service package name to bind to by default. -->
+    <string name="config_wwan_network_service_package" translatable="false">com.android.phone</string>
+
+    <!-- Cellular network service class name to bind to by default.-->
+    <string name="config_wwan_network_service_class" translatable="false"></string>
+
+    <!-- IWLAN network service package name to bind to by default. If none is specified in an overlay, an
+         empty string is passed in -->
+    <string name="config_wlan_network_service_package" translatable="false"></string>
+
+    <!-- IWLAN network service class name to bind to by default. If none is specified in an overlay, an
+         empty string is passed in -->
+    <string name="config_wlan_network_service_class" translatable="false"></string>
+
+    <!-- Telephony qualified networks service package name to bind to by default. -->
+    <string name="config_qualified_networks_service_package" translatable="false"></string>
+
+    <!-- Telephony qualified networks service class name to bind to by default. -->
+    <string name="config_qualified_networks_service_class" translatable="false"></string>
+
+    <!-- Cellular data service package name to bind to by default. If none is specified in an overlay, an
+         empty string is passed in -->
+    <string name="config_wwan_data_service_package" translatable="false">com.android.phone</string>
+
+    <!-- IWLAN data service package name to bind to by default. If none is specified in an overlay, an
+         empty string is passed in -->
+    <string name="config_wlan_data_service_package" translatable="false"></string>
+
+    <!-- Cellular data service class name to bind to by default. If none is specified in an overlay, an
+         empty string is passed in -->
+    <string name="config_wwan_data_service_class" translatable="false"></string>
+
+    <!-- IWLAN data service class name to bind to by default. If none is specified in an overlay, an
+         empty string is passed in -->
+    <string name="config_wlan_data_service_class" translatable="false"></string>
+
+    <!-- Boolean indicating if RADIO POWER OFF is required on receiving SIM REFRESH with RESET.
+         This will be handled by modem if it is false. -->
+    <bool name="config_requireRadioPowerOffOnSimRefreshReset">false</bool>
+
+    <!-- Flag specifying whether the device will use the "allow_hold_in_ims_call" carrier config
+         option.  When false, the device will support holding of IMS calls, regardless of the
+         carrier config setting. -->
+    <bool name="config_device_respects_hold_carrier_config">true</bool>
+
+    <!-- Whether to use voip audio mode for ims call -->
+    <bool name="config_use_voip_mode_for_ims">false</bool>
+
+    <!-- Enables built-in SIP phone capability -->
+    <bool name="config_built_in_sip_phone">true</bool>
+
+    <!-- Flag indicating apps will skip sending hold request before merge. In this case
+        IMS service implementation will do both.i.e.hold followed by merge. -->
+    <bool name="skipHoldBeforeMerge">true</bool>
+
+    <!-- Flag specifying whether VoLTE is available on device -->
+    <bool name="config_device_volte_available">false</bool>
+
+    <!-- Flag specifying whether VT is available on device -->
+    <bool name="config_device_vt_available">false</bool>
+
+    <!-- Flag specifying whether WFC over IMS is available on device -->
+    <bool name="config_device_wfc_ims_available">false</bool>
+
+    <!-- Flag specifying whether or not IMS will use the dynamic ImsResolver -->
+    <bool name="config_dynamic_bind_ims">false</bool>
+
+    <!-- ImsService package name to bind to by default. If none is specified in an overlay, an
+         empty string is passed in -->
+    <string name="config_ims_package"/>
+
+    <!-- Whether cbrs is supported on the device or not -->
+    <bool name="config_cbrs_supported" translatable="false">false</bool>
+
+    <!-- Enables SIP on WIFI only -->
+    <bool name="config_sip_wifi_only">false</bool>
+
+    <!-- Name of the dialog that is used to install the carrier app when the SIM is inserted -->
+    <string name="config_carrierAppInstallDialogComponent" translatable="false"
+            >com.android.simappdialog/com.android.simappdialog.InstallCarrierAppActivity</string>
+
+    <!-- The default mobile provisioning apn. Empty by default, maybe overridden by
+         an mcc/mnc specific config.xml -->
+    <string name="mobile_provisioning_apn" translatable="false"></string>
+
+    <!-- Number of retries Cell Data should attempt for a given error code before
+         restarting the modem.
+         Error codes not listed will not lead to modem restarts.
+         Array of "code#,retry#"  -->
+    <string-array name="config_cell_retries_per_error_code">
+    </string-array>
+
+    <bool name="config_auto_attach_data_on_creation">true</bool>
+
+    <!-- Set to true if after a provisioning apn the radio should be restarted -->
+    <bool name="config_restartRadioAfterProvisioning">false</bool>
+
+    <!-- When true, indicates that the vendor's IMS implementation requires a workaround when
+         sending a request to enable or disable the camera while the video session is also
+         paused. -->
+    <bool name="config_useVideoPauseWorkaround">false</bool>
+
+    <!-- Use ERI text for network name on CDMA LTE -->
+    <bool name="config_LTE_eri_for_network_name">true</bool>
+
+    <!-- Flag indicating if the user is notified when the mobile network access is restricted -->
+    <bool name="config_user_notification_of_restrictied_mobile_access">true</bool>
+
+    <!-- Component name of the ICC hotswap prompt for restart dialog -->
+    <string name="config_iccHotswapPromptForRestartDialogComponent" translatable="false">@null</string>
+
+    <!-- call barring MMI code from TS 22.030 Annex B -->
+    <string-array translatable="false" name="config_callBarringMMI">
+        <item>33</item>
+        <item>331</item>
+        <item>332</item>
+        <item>35</item>
+        <item>351</item>
+        <item>330</item>
+        <item>333</item>
+        <item>353</item>
+    </string-array>
+
+    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+    <string-array name="config_twoDigitNumberPattern" translatable="false">
+    </string-array>
+
+    <!-- A array of regex to treat a SMS as VVM SMS if the message body matches.
+         Each item represents an entry, which consists of two parts:
+         a comma (,) separated list of MCCMNC the regex applies to, followed by a semicolon (;), and
+         then the regex itself. -->
+    <string-array name="config_vvmSmsFilterRegexes" translatable="false">
+        <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS-->
+        <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item>
+    </string-array>
+
+    <!-- default telephony hardware configuration for this platform.
+    -->
+    <!-- this string array should be overridden by the device to present a list
+         telephony hardware resource.  this is used by the telephony device controller
+         (TDC) to offer the basic capabilities of the hardware to the telephony
+         framework
+    -->
+    <!-- an array of "[hardware type],[hardware-uuid],[state],[[hardware-type specific]]"
+         with, [[hardware-type specific]] in:
+            - "[[ril-model],[rat],[max-active-voice],[max-active-data],[max-active-standby]]"
+              for 'modem' hardware
+            - "[[associated-modem-uuid]]"
+              for 'sim' hardware.
+         refer to HardwareConfig in com.android.internal.telephony for specific details/values
+         those elements can carry.
+    -->
+    <string-array translatable="false" name="config_telephonyHardware">
+        <!-- modem -->
+        <item>0,modem,0,0,0,1,1,1</item>
+        <!-- sim -->
+        <item>1,sim,0,modem</item>
+    </string-array>
+
+    <!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] -->
+    <string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastservice
+    </string>
+
+    <!-- For some operators, PDU has garbages. To fix it, need to use valid index -->
+    <integer name="config_valid_wappush_index">-1</integer>
+
+    <!-- Set to true if we need to not prefer an APN.
+         This is being added to enable a simple scenario of pre-paid
+         provisioning on some carriers, working around a bug (7305641)
+         where if the preferred is used we don't try the others. -->
+    <bool name="config_dontPreferApn">false</bool>
+
+</resources>
diff --git a/res/values/overlayable.xml b/res/values/overlayable.xml
new file mode 100644
index 0000000..1bbad36
--- /dev/null
+++ b/res/values/overlayable.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<!-- The collection of resources for theming the appearance of a device -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <overlayable name="TelephonyCustomization">
+
+        <!-- START VENDOR CUSTOMIZATION -->
+        <policy type="product|system|vendor">
+            <item type="string" name="config_mms_user_agent"/>
+            <item type="string" name="config_mms_user_agent_profile_url"/>
+            <item type="bool" name="config_switch_phone_on_voice_reg_state_change"/>
+            <item type="bool" name="skip_restoring_network_selection"/>
+            <item type="bool" name="config_hotswapCapable"/>
+            <item type="array" name="config_cdma_international_roaming_indicators"/>
+            <item type="integer" name="config_mobile_mtu"/>
+            <item type="array" name="config_mobile_tcp_buffers"/>
+            <item type="bool" name="config_use_sim_language_file"/>
+            <item type="bool" name="config_requireRadioPowerOffOnSimRefreshReset"/>
+            <item type="bool" name="config_device_respects_hold_carrier_config"/>
+            <item type="array" name="config_display_no_service_when_sim_unready"/>
+            <item type="array" name="config_telephonyEuiccDeviceCapabilities"/>
+            <item type="integer" name="config_num_physical_slots"/>
+            <item type="bool" name="config_duplicate_port_omadm_wappush"/>
+            <item type="string" name="config_wwan_network_service_package"/>
+            <item type="string" name="config_wwan_network_service_class"/>
+            <item type="string" name="config_wlan_network_service_package"/>
+            <item type="string" name="config_wlan_network_service_class"/>
+            <item type="string" name="config_qualified_networks_service_package"/>
+            <item type="string" name="config_qualified_networks_service_class"/>
+            <item type="string" name="config_wwan_data_service_package"/>
+            <item type="string" name="config_wwan_data_service_class"/>
+            <item type="string" name="config_wlan_data_service_package"/>
+            <item type="string" name="config_wlan_data_service_class"/>
+            <item type="bool" name="config_use_voip_mode_for_ims"/>
+            <item type="bool" name="config_built_in_sip_phone"/>
+            <item type="bool" name="skipHoldBeforeMerge"/>
+            <item type="bool" name="config_device_volte_available"/>
+            <item type="bool" name="config_device_vt_available"/>
+            <item type="bool" name="config_device_wfc_ims_available"/>
+            <item type="bool" name="config_dynamic_bind_ims"/>
+            <item type="string" name="config_ims_package"/>
+            <item type="string" name="config_carrierAppInstallDialogComponent"/>
+            <item type="bool" name="config_cbrs_supported"/>
+            <item type="bool" name="config_sip_wifi_only"/>
+            <item type="string" name="mobile_provisioning_apn"/>
+            <item type="array" name="config_cell_retries_per_error_code"/>
+            <item type="bool" name="config_auto_attach_data_on_creation"/>
+            <item type="bool" name="config_restartRadioAfterProvisioning"/>
+            <item type="bool" name="config_useVideoPauseWorkaround"/>
+            <item type="bool" name="config_LTE_eri_for_network_name"/>
+            <item type="bool" name="config_user_notification_of_restrictied_mobile_access"/>
+            <item type="string" name="config_iccHotswapPromptForRestartDialogComponent"/>
+            <item type="array" name="config_callBarringMMI"/>
+            <item type="array" name="config_twoDigitNumberPattern"/>
+            <item type="array" name="config_vvmSmsFilterRegexes"/>
+            <item type="array" name="config_telephonyHardware"/>
+            <item type="string" name="cellbroadcast_default_package"/>
+            <item type="integer" name="config_valid_wappush_index"/>
+            <item type="bool" name="config_dontPreferApn"/>
+          </policy>
+        <!-- END VENDOR CUSTOMIZATION -->
+
+    </overlayable>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..5cf34ec
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,412 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2020, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Do Not Translate: Alternate eri.xml -->
+    <string name="alternate_eri_file">/data/eri.xml</string>
+
+    <!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale. The wifi regulatory domain is extracted from the locale information. This is used at startup to set system defaults by checking the system property ro.carrier for the carrier-id and searching through this array -->
+    <!-- An Array of [[Carrier-ID]                     -->
+    <!--              [default-locale]]                -->
+    <string-array name="carrier_properties" translatable="false">
+    </string-array>
+
+    <!-- For GsmMmiCode.java --> <skip />
+    <!-- Displayed when the user dialed an MMI code whose function
+         could not be performed. This will be displayed in a toast. -->
+    <string name="mmiError">Connection problem or invalid MMI code.</string>
+    <!-- Displayed when the user dialed an MMI code whose function
+         could not be performed because FDN is enabled. This will be displayed in a toast. -->
+    <string name="mmiFdnError">Operation is restricted to fixed dialing numbers only.</string>
+    <!-- Displayed when a carrier does not support call forwarding queries when roaming. -->
+    <string name="mmiErrorWhileRoaming">Can not change call forwarding settings from your phone while you are roaming.</string>
+
+    <!-- What the UI should display for "voice mail" unless overridden by the SIM-->
+    <string name="defaultVoiceMailAlphaTag">Voicemail</string>
+
+    <!-- Displayed when a phone feature such as call barring was activated. -->
+    <string name="serviceEnabled">Service was enabled.</string>
+    <!-- Displayed in front of the list of a set of service classes
+         (voice, data, fax, etc.) that were enabled. -->
+    <string name="serviceEnabledFor">Service was enabled for:</string>
+    <!-- Displayed when a phone feature such as call forwarding was deactivated. -->
+    <string name="serviceDisabled">Service has been disabled.</string>
+    <!-- Displayed when a phone property such as a SIM password was registered. -->
+    <string name="serviceRegistered">Registration was successful.</string>
+    <!-- Displayed when a phone property such as a SIM password was erased. -->
+    <string name="serviceErased">Erasure was successful.</string>
+    <!-- Displayed when a SIM password was entered incorrectly. -->
+    <string name="passwordIncorrect">Incorrect password.</string>
+    <!-- Displayed when a phone feature triggered by an MMI code is complete. -->
+    <string name="mmiComplete">MMI complete.</string>
+    <!-- Displayed when a SIM PIN password is entered incorrectly. -->
+    <string name="badPin">The old PIN you typed isn\'t correct.</string>
+    <!-- Displayed when a SIM PUK password is entered incorrectly. -->
+    <string name="badPuk">The PUK you typed isn\'t correct.</string>
+    <!-- Displayed when SIM PIN passwords are entered inconsistently. -->
+    <string name="mismatchPin">The PINs you typed don\'t match.</string>
+    <!-- Displayed when a SIM PIN password is too long or too short. -->
+    <string name="invalidPin">Type a PIN that is 4 to 8 numbers.</string>
+    <!-- Displayed when a SIM PUK password is too short. -->
+    <string name="invalidPuk">Type a PUK that is 8 numbers or longer.</string>
+    <!-- Displayed to prompt the user to type the PUK password to unlock
+         the SIM card. -->
+    <string name="needPuk">Your SIM card is PUK-locked. Type the PUK code to unlock it.</string>
+    <string name="needPuk2">Type PUK2 to unblock SIM card.</string>
+    <!-- Displayed when user attempts to change SIM PIN1 without enabling PIN1. -->
+    <string name="enablePin">Unsuccessful, enable SIM/RUIM Lock.</string>
+    <!-- Displayed when a SIM PIN/PUK is entered incorrectly. -->
+    <plurals name="pinpuk_attempts">
+        <item quantity="one">You have <xliff:g id="number">%d</xliff:g> remaining attempt before SIM is locked.</item>
+        <item quantity="other">You have <xliff:g id="number">%d</xliff:g> remaining attempts before SIM is locked.</item>
+    </plurals>
+    <!-- Title for the dialog used to display the user's IMEI number [CHAR LIMIT=10] -->
+    <string name="imei">IMEI</string>
+
+    <!-- Title for the dialog used to display the user's MEID number on CDMA network
+         [CHAR LIMIT=10] -->
+    <string name="meid">MEID</string>
+
+    <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
+    <string name="ClipMmi">Incoming Caller ID</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
+    <string name="ClirMmi">Outgoing Caller ID</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID. -->
+    <string name="ColpMmi">Connected Line ID</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction. -->
+    <string name="ColrMmi">Connected Line ID Restriction</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling call forwarding. -->
+    <string name="CfMmi">Call forwarding</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling call waiting. -->
+    <string name="CwMmi">Call waiting</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling call barring. -->
+    <string name="BaMmi">Call barring</string>
+    <!-- Displayed as the title for a success/failure report changing the SIM password. -->
+    <string name="PwdMmi">Password change</string>
+    <!-- Displayed as the title for a success/failure report changing the SIM PIN. -->
+    <string name="PinMmi">PIN change</string>
+    <string name="CnipMmi">Calling number present</string>
+    <string name="CnirMmi">Calling number restricted</string>
+    <string name="ThreeWCMmi">Three way calling</string>
+    <string name="RuacMmi">Rejection of undesired annoying calls</string>
+    <string name="CndMmi">Calling number delivery</string>
+    <string name="DndMmi">Do not disturb</string>
+
+    <!-- Displayed to confirm to the user that caller ID will be restricted on the next call as usual. -->
+    <string name="CLIRDefaultOnNextCallOn">Caller ID defaults to restricted. Next call: Restricted</string>
+    <!-- Displayed to confirm to the user that caller ID will be not restricted on the next call even though it usually is. -->
+    <string name="CLIRDefaultOnNextCallOff">Caller ID defaults to restricted. Next call: Not restricted</string>
+    <!-- Displayed to confirm to the user that caller ID will not be restricted on the next call but usually is. -->
+    <string name="CLIRDefaultOffNextCallOn">Caller ID defaults to not restricted. Next call: Restricted</string>
+    <!-- Displayed to confirm to the user that caller ID will not be restricted on the next call or in general. -->
+    <string name="CLIRDefaultOffNextCallOff">Caller ID defaults to not restricted. Next call: Not restricted</string>
+
+
+    <!-- Displayed to tell the user that caller ID is not provisioned for their SIM. -->
+    <string name="serviceNotProvisioned">Service not provisioned.</string>
+    <!-- Displayed to tell the user that they cannot change the caller ID setting. -->
+    <string name="CLIRPermanent">You can\'t change the caller ID setting.</string>
+
+    <!-- Notification title to tell the user that data service is blocked by access control. [CHAR LIMIT=NOTIF_TITLE] -->
+    <string name="RestrictedOnDataTitle">No mobile data service</string>
+    <!-- Notification title to tell the user that emergency calling is blocked by access control. [CHAR LIMIT=NOTIF_TITLE] -->
+    <string name="RestrictedOnEmergencyTitle">Emergency calling unavailable</string>
+    <!-- Notification title to tell the user that normal service is blocked by access control. [CHAR LIMIT=NOTIF_TITLE] -->
+    <string name="RestrictedOnNormalTitle">No voice service</string>
+    <!-- Notification title to tell the user that all emergency and normal voice services are blocked by access control. [CHAR LIMIT=NOTIF_TITLE] -->
+    <string name="RestrictedOnAllVoiceTitle">No voice service or emergency calling</string>
+
+    <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control. [CHAR LIMIT=NOTIF_BODY] -->
+    <string name="RestrictedStateContent">Temporarily turned off by your carrier</string>
+
+    <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control when multiple SIMs are active. [CHAR LIMIT=NOTIF_BODY] -->
+    <string name="RestrictedStateContentMsimTemplate">Temporarily turned off by your carrier for SIM <xliff:g id="simNumber" example="1">%d</xliff:g></string>
+
+    <!-- Displayed to tell the user that they should switch their network preference. -->
+    <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach mobile network</string>
+    <!-- Displayed to tell the user that they should switch their network preference. -->
+    <string name="NetworkPreferenceSwitchSummary">Try changing preferred network. Tap to change.</string>
+    <!-- Displayed to tell the user that emergency calls might not be available. -->
+    <string name="EmergencyCallWarningTitle">Emergency calling unavailable</string>
+    <!-- Displayed to tell the user that emergency calls might not be available. -->
+    <string name="EmergencyCallWarningSummary">Can\u2019t make emergency calls over Wi\u2011Fi</string>
+
+    <!-- Telephony notification channel name for a channel containing network alert notifications. -->
+    <string name="notification_channel_network_alert">Alerts</string>
+    <!-- Telephony notification channel name for a channel containing call forwarding notifications. -->
+    <string name="notification_channel_call_forward">Call forwarding</string>
+    <!-- Telephony notification channel name for a channel containing emergency callback mode notifications. -->
+    <string name="notification_channel_emergency_callback">Emergency callback mode</string>
+    <!-- Telephony notification channel name for a channel containing mobile data status notifications. -->
+    <string name="notification_channel_mobile_data_status">Mobile data status</string>
+    <!-- Telephony notification channel name for a channel containing sms notifications. -->
+    <string name="notification_channel_sms">SMS messages</string>
+    <!-- Telephony notification channel name for a channel containing voice mail notifications. -->
+    <string name="notification_channel_voice_mail">Voicemail messages</string>
+    <!-- Telephony notification channel name for a channel containing wifi calling status notifications. -->
+    <string name="notification_channel_wfc">Wi-Fi calling</string>
+    <!-- Telephony notification channel name for a channel containing SIM notifications -->
+    <string name="notification_channel_sim">SIM status</string>
+    <!-- Telephony notification channel name for a channel containing high priority SIM notifications -->
+    <string name="notification_channel_sim_high_prio">High priority SIM status</string>
+
+    <!-- Displayed to tell the user that peer changed TTY mode -->
+    <string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
+    <string name="peerTtyModeHco">Peer requested TTY Mode HCO</string>
+    <string name="peerTtyModeVco">Peer requested TTY Mode VCO</string>
+    <string name="peerTtyModeOff">Peer requested TTY Mode OFF</string>
+
+    <!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
+    <!-- Example: Service was enabled for: Voice, Data -->
+    <string name="serviceClassVoice">Voice</string>
+    <!-- Example: Service was enabled for: Voice, Data -->
+    <string name="serviceClassData">Data</string>
+    <!-- Example: Service was enabled for: Voice, FAX -->
+    <string name="serviceClassFAX">FAX</string>
+    <!-- Example: Service was enabled for: Voice, SMS -->
+    <string name="serviceClassSMS">SMS</string>
+    <!-- Meaning: asynchronous data.  Example: Service was enabled for: Voice, Async -->
+    <string name="serviceClassDataAsync">Async</string>
+    <!-- Meaning: synchronous data.  Example: Service was enabled for: Voice, Async -->
+    <string name="serviceClassDataSync">Sync</string>
+    <!-- Meaning: packet data.  Example: Service was enabled for: Voice, Packet -->
+    <string name="serviceClassPacket">Packet</string>
+    <!-- Meaning: unknown.  Example: Service was enabled for: Voice, PAD -->
+    <string name="serviceClassPAD">PAD</string>
+
+    <!-- CDMA Roaming Indicator Strings (non ERI)--> <skip />
+    <!-- Default roaming indicator text -->
+    <string name="roamingText0">Roaming Indicator On</string>
+    <string name="roamingText1">Roaming Indicator Off</string>
+    <string name="roamingText2">Roaming Indicator Flashing</string>
+    <string name="roamingText3">Out of Neighborhood</string>
+    <string name="roamingText4">Out of Building</string>
+    <string name="roamingText5">Roaming - Preferred System</string>
+    <string name="roamingText6">Roaming - Available System</string>
+    <string name="roamingText7">Roaming - Alliance Partner</string>
+    <string name="roamingText8">Roaming - Premium Partner</string>
+    <string name="roamingText9">Roaming - Full Service Functionality</string>
+    <string name="roamingText10">Roaming - Partial Service Functionality</string>
+    <string name="roamingText11">Roaming Banner On</string>
+    <string name="roamingText12">Roaming Banner Off</string>
+    <string name="roamingTextSearching">Searching for Service</string>
+
+    <!-- Displayed when WFC registration fails -->
+    <string name="wfcRegErrorTitle">Couldn\u2019t set up Wi\u2011Fi calling</string>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings. (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Issue registering Wi\u2011Fi calling with your carrier: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g></item>
+    </string-array>
+    <!-- Template for showing mobile network operator name while WFC is active -->
+    <string-array name="wfcSpnFormats" translatable="false">
+        <item>@string/wfcSpnFormat_spn</item>
+        <item>@string/wfcSpnFormat_spn_wifi_calling</item>
+        <item>@string/wfcSpnFormat_wlan_call</item>
+        <item>@string/wfcSpnFormat_spn_wlan_call</item>
+        <item>@string/wfcSpnFormat_spn_wifi</item>
+        <item>@string/wfcSpnFormat_wifi_calling_bar_spn</item>
+        <item>@string/wfcSpnFormat_spn_vowifi</item>
+        <item>@string/wfcSpnFormat_wifi_calling</item>
+        <item>@string/wfcSpnFormat_wifi</item>
+        <item>@string/wfcSpnFormat_wifi_calling_wo_hyphen</item>
+        <item>@string/wfcSpnFormat_vowifi</item>
+        <item>@string/wfcSpnFormat_spn_wifi_calling_vo_hyphen</item>
+    </string-array>
+
+    <!-- Ims supported call barring MMI code -->
+    <string-array translatable="false" name="config_callBarringMMI_for_ims">
+        <item>33</item>
+        <item>331</item>
+        <item>332</item>
+        <item>35</item>
+        <item>351</item>
+        <item>330</item>
+        <item>333</item>
+        <item>353</item>
+      </string-array>
+
+    <!-- Spn during Wi-Fi Calling: "<operator>" -->
+    <string name="wfcSpnFormat_spn"><xliff:g id="spn" example="Operator">%s</xliff:g></string>
+    <!-- Spn during Wi-Fi Calling: "<operator> Wi-Fi Calling" -->
+    <string name="wfcSpnFormat_spn_wifi_calling"><xliff:g id="spn" example="Operator">%s</xliff:g> Wi-Fi Calling</string>
+    <!-- Spn during Wi-Fi Calling: "<operator> WiFi Calling" -->
+    <string name="wfcSpnFormat_spn_wifi_calling_vo_hyphen"><xliff:g id="spn" example="Operator">%s</xliff:g> WiFi Calling</string>
+    <!-- Spn during Wi-Fi Calling: "WLAN Call" -->
+    <string name="wfcSpnFormat_wlan_call">WLAN Call</string>
+    <!-- Spn during Wi-Fi Calling: "<operator> WLAN Call" -->
+    <string name="wfcSpnFormat_spn_wlan_call"><xliff:g id="spn" example="Operator">%s</xliff:g> WLAN Call</string>
+    <!-- Spn during Wi-Fi Calling: "<operator> Wi-Fi" -->
+    <string name="wfcSpnFormat_spn_wifi"><xliff:g id="spn" example="Operator">%s</xliff:g> Wi-Fi</string>
+    <!-- Spn during Wi-Fi Calling: "WiFi Calling | <operator>" -->
+    <string name="wfcSpnFormat_wifi_calling_bar_spn">WiFi Calling | <xliff:g id="spn" example="Operator">%s</xliff:g></string>
+    <!-- Spn during Wi-Fi Calling: "<operator> VoWifi" -->
+    <string name="wfcSpnFormat_spn_vowifi"><xliff:g id="spn" example="Operator">%s</xliff:g> VoWifi</string>
+    <!-- Spn during Wi-Fi Calling: "Wi-Fi Calling" -->
+    <string name="wfcSpnFormat_wifi_calling">Wi-Fi Calling</string>
+    <!-- Spn during Wi-Fi Calling: "Wi-Fi" -->
+    <string name="wfcSpnFormat_wifi">Wi-Fi</string>
+    <!-- Spn during Wi-Fi Calling: "WiFi Calling" (without hyphen) -->
+    <string name="wfcSpnFormat_wifi_calling_wo_hyphen">WiFi Calling</string>
+    <!-- Spn during Wi-Fi Calling: "VoWifi" -->
+    <string name="wfcSpnFormat_vowifi">VoWifi</string>
+
+    <!--
+        {0} is one of "bearerServiceCode*"
+        {1} is dialing number
+        {2} is time in seconds
+
+        cfTemplateRegistered and cfTemplateRegisteredTime mean that a phone number
+        has been set but forwarding is not on.
+    --> <skip />
+    <!-- Displayed when the call forwarding query was not able to be forwarded. -->
+    <string name="cfTemplateNotForwarded"><xliff:g id="bearer_service_code">{0}</xliff:g>: Not forwarded</string>
+    <!-- Displayed when the call forwarding query was forwarded. -->
+    <string name="cfTemplateForwarded"><xliff:g id="bearer_service_code">{0}</xliff:g>: <xliff:g id="dialing_number">{1}</xliff:g></string>
+    <!-- Displayed when the call forwarding query will be forwarded after some time. -->
+    <string name="cfTemplateForwardedTime"><xliff:g id="bearer_service_code">{0}</xliff:g>: <xliff:g id="dialing_number">{1}</xliff:g> after <xliff:g id="time_delay">{2}</xliff:g> seconds</string>
+    <!-- Displayed when the call forwarding query was set but forwarding is not enabled. -->
+    <string name="cfTemplateRegistered"><xliff:g id="bearer_service_code">{0}</xliff:g>: Not forwarded</string>
+    <!-- Displayed when the call forwarding query was set but forwarding is not enabled. -->
+    <string name="cfTemplateRegisteredTime"><xliff:g id="bearer_service_code">{0}</xliff:g>: Not forwarded</string>
+
+    <!-- SMS per-application rate control Dialog --> <skip />
+    <!-- SMS_DIALOG: An SMS dialog is shown if an application tries to send too many SMSes.  This is the title of that dialog. -->
+    <string name="sms_control_title">Sending SMS messages</string>
+    <!-- See SMS_DIALOG.  This is the message shown in that dialog. [CHAR LIMIT=NONE] -->
+    <string name="sms_control_message">&lt;b><xliff:g id="app_name">%1$s</xliff:g>&lt;/b> is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?</string>
+    <!-- See SMS_DIALOG.  This is a button choice to allow sending the SMSes. [CHAR LIMIT=30] -->
+    <string name="sms_control_yes">Allow</string>
+    <!-- See SMS_DIALOG.  This is a button choice to disallow sending the SMSes. [CHAR LIMIT=30] -->
+    <string name="sms_control_no">Deny</string>
+
+    <!-- SMS short code verification dialog. --> <skip />
+    <!-- The message text for the SMS short code confirmation dialog. [CHAR LIMIT=NONE] -->
+    <string name="sms_short_code_confirm_message">&lt;b><xliff:g id="app_name">%1$s</xliff:g>&lt;/b> would like to send a message to &lt;b><xliff:g id="dest_address">%2$s</xliff:g>&lt;/b>.</string>
+    <!-- Message details for the SMS short code confirmation dialog (possible premium short code). [CHAR LIMIT=NONE] -->
+    <string name="sms_short_code_details">This <b>may cause charges</b> on your mobile account.</string>
+    <!-- Message details for the SMS short code confirmation dialog (premium short code). [CHAR LIMIT=NONE] -->
+    <string name="sms_premium_short_code_details"><b>This will cause charges on your mobile account.</b></string>
+    <!-- Text of the approval button for the SMS short code confirmation dialog. [CHAR LIMIT=30] -->
+    <string name="sms_short_code_confirm_allow">Send</string>
+    <!-- Text of the cancel button for the SMS short code confirmation dialog. [CHAR LIMIT=30] -->
+    <string name="sms_short_code_confirm_deny">Cancel</string>
+    <!-- Text of the checkbox for the SMS short code confirmation dialog to remember the user's choice. [CHAR LIMIT=40] -->
+    <string name="sms_short_code_remember_choice">Remember my choice</string>
+    <!-- Text shown when remember checkbox is checked to inform the user how they may undo the setting. [CHAR LIMIT=40] -->
+    <string name="sms_short_code_remember_undo_instruction">You can change this later in Settings\u00A0>\u00A0Apps"</string>
+
+    <!-- Text of the approval button for the SMS short code confirmation dialog when checkbox is checked. [CHAR LIMIT=30] -->
+    <string name="sms_short_code_confirm_always_allow">Always Allow</string>
+    <!-- Text of the cancel button for the SMS short code confirmation dialog when checkbox is checked. [CHAR LIMIT=30] -->
+    <string name="sms_short_code_confirm_never_allow">Never Allow</string>
+
+    <!-- SIM swap and device reboot Dialog --> <skip />
+    <!-- See SIM_REMOVED_DIALOG.  This is the title of that dialog. -->
+    <string name="sim_removed_title">SIM card removed</string>
+    <!-- See SIM_REMOVED_DIALOG.  This is the message of that dialog. -->
+    <string name="sim_removed_message">The mobile network will be unavailable until you restart with a valid SIM card inserted.</string>
+    <!-- See SIM_REMOVED_DIALOG.  This is the button of that dialog. -->
+    <string name="sim_done_button">Done</string>
+    <!-- See SIM_ADDED_DIALOG.  This is the title of that dialog. -->
+    <string name="sim_added_title">SIM card added</string>
+    <!-- See SIM_ADDED_DIALOG.  This is the message of that dialog. -->
+    <string name="sim_added_message">Restart your device to access the mobile network.</string>
+    <!-- See SIM_ADDED_DIALOG.  This is the button of that dialog. -->
+    <string name="sim_restart_button">Restart</string>
+    <!-- See Carrier_App_Dialog. This is the message of that dialog. -->
+    <string name="install_carrier_app_notification_title">Activate mobile service</string>
+    <!-- Notification message that shows when the user inserts a SIM card that requires a carrier app download, but the app name is unknown -->
+    <string name="install_carrier_app_notification_text">Download the carrier app to activate your new SIM</string>
+    <!-- Notification message that shows when the user inserts a SIM card that requires a carrier app download.  App name is known -->
+    <string name="install_carrier_app_notification_text_app_name">Download the <xliff:g id="app_name">%1$s</xliff:g> app to activate your new SIM</string>
+
+    <!-- See Carrier_App_Notification. This is the button of that dialog. -->
+    <string name="install_carrier_app_notification_button">Download app</string>
+    <!-- See carrier_app_notification. This is the headline. -->
+    <string name="carrier_app_notification_title">New SIM inserted</string>
+    <string name="carrier_app_notification_text">Tap to set it up</string>
+
+    <!-- STK sending DTMF, SMS, USSD, SS -->
+    <string name="sending">Sending\u2026</string>
+
+    <!-- STK launch Browser -->
+    <string name="launchBrowserDefault">Launch Browser?</string>
+
+    <!-- STK setup Call -->
+    <string name="SetupCallDefault">Accept call?</string>
+
+    <!-- Displayed when the USSD/SS request is modified by STK CC to a
+    different request. This will be displayed in a toast. -->
+    <string name="stk_cc_ussd_to_dial">USSD request changed to regular call</string>
+    <string name="stk_cc_ussd_to_ss">USSD request changed to SS request</string>
+    <string name="stk_cc_ussd_to_ussd">Changed to new USSD request</string>
+    <string name="stk_cc_ussd_to_dial_video">USSD request changed to video call</string>
+    <string name="stk_cc_ss_to_dial">SS request changed to regular call</string>
+    <string name="stk_cc_ss_to_dial_video">SS request changed to video call</string>
+    <string name="stk_cc_ss_to_ussd">SS request changed to USSD request</string>
+    <string name="stk_cc_ss_to_ss">Changed to new SS request</string>
+
+    <!-- Notification title shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
+    <string name="new_sms_notification_title">You have new messages</string>
+    <!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
+    <string name="new_sms_notification_content">Open SMS app to view</string>
+
+    <!-- Label used by Telephony code, assigned as the display name for conference calls [CHAR LIMIT=60] -->
+    <string name="conference_call">Conference Call</string>
+
+    <!-- Title of notification when UE fails CS registration with MM reject cause code from network. -->
+    <string name="mmcc_authentication_reject">SIM not allowed for voice</string>
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned for voice</string>
+    <string name="mmcc_illegal_ms">SIM not allowed for voice</string>
+    <string name="mmcc_illegal_me">Phone not allowed for voice</string>
+
+    <!-- Title of notification when UE fails to register network with MM reject cause code when multiple SIMs are active. -->
+    <string name="mmcc_authentication_reject_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+    <string name="mmcc_imsi_unknown_in_hlr_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not provisioned</string>
+    <string name="mmcc_illegal_ms_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+    <string name="mmcc_illegal_me_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+
+    <!-- Shown in the lock screen when there is emergency calls only mode. -->
+    <string name="emergency_calls_only" msgid="2485604591272668370">Emergency calls only</string>
+
+    <!-- On the keyguard screen, it shows the carrier the phone is connected to.  This is displayed if the phone is not connected to a carrier.-->
+    <string name="lockscreen_carrier_default">No service</string>
+
+    <!-- Status message for a remote route attempting to connect -->
+    <string name="media_route_status_connecting">Connecting...</string>
+
+    <!-- WFC, summary for Disabled -->
+    <string name="wifi_calling_off_summary">Off</string>
+    <!-- WFC, summary for Wi-Fi Preferred -->
+    <string name="wfc_mode_wifi_preferred_summary">Call over Wi-Fi</string>
+    <!-- WFC, summary for Mobile data Preferred -->
+    <string name="wfc_mode_cellular_preferred_summary">Call over mobile network</string>
+    <!-- WFC, summary for Wi-Fi Only -->
+    <string name="wfc_mode_wifi_only_summary">Wi-Fi only</string>
+
+    <!-- Sequence of characters used to separate message strings in keyguard. Typically just em-dash
+         with spaces on either side. [CHAR LIMIT=3] -->
+    <string name="kg_text_message_separator" product="default">" \u2014 "</string>
+
+</resources>
diff --git a/src/java/com/android/internal/telephony/AppSmsManager.java b/src/java/com/android/internal/telephony/AppSmsManager.java
index 30de674..f473c9a 100644
--- a/src/java/com/android/internal/telephony/AppSmsManager.java
+++ b/src/java/com/android/internal/telephony/AppSmsManager.java
@@ -20,16 +20,10 @@
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
-import android.app.role.IRoleManager;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.IFinancialSmsCallback;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
 import android.telephony.SubscriptionManager;
@@ -147,24 +141,6 @@
     }
 
     /**
-     * Get filtered SMS messages for financial app.
-     */
-    public void getSmsMessagesForFinancialApp(
-            String callingPkg, Bundle params, final IFinancialSmsCallback callback) {
-        try {
-            IRoleManager roleManager = IRoleManager.Stub.asInterface(
-                    ServiceManager.getServiceOrThrow(Context.ROLE_SERVICE));
-            roleManager.getSmsMessagesForFinancialApp(callingPkg, params, callback);
-        } catch (RemoteException e) {
-            Log.e(LOG_TAG, "Receive RemoteException.");
-            // do nothing
-        } catch (ServiceNotFoundException e) {
-            Log.e(LOG_TAG, "Service not found.");
-            // do nothing
-        }
-    }
-
-    /**
      * Handle an incoming SMS_DELIVER_ACTION intent if it is an app-only SMS.
      */
     public boolean handleSmsReceivedIntent(Intent intent) {
diff --git a/src/java/com/android/internal/telephony/AsyncEmergencyContactNotifier.java b/src/java/com/android/internal/telephony/AsyncEmergencyContactNotifier.java
index 820a052..34fae4a 100644
--- a/src/java/com/android/internal/telephony/AsyncEmergencyContactNotifier.java
+++ b/src/java/com/android/internal/telephony/AsyncEmergencyContactNotifier.java
@@ -19,12 +19,12 @@
 import android.content.Context;
 import android.os.AsyncTask;
 import android.provider.BlockedNumberContract;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 /**
  * An {@link AsyncTask} that notifies the Blocked number provider that emergency services were
- * contacted. See {@link BlockedNumberContract.SystemContract#notifyEmergencyContact(Context)}
- * for details.
+ * contacted.
  * {@hide}
  */
 public class AsyncEmergencyContactNotifier extends AsyncTask<Void, Void, Void> {
@@ -39,10 +39,27 @@
     @Override
     protected Void doInBackground(Void... params) {
         try {
-            BlockedNumberContract.SystemContract.notifyEmergencyContact(mContext);
+            notifyEmergencyContact(mContext);
         } catch (Exception e) {
             Rlog.e(TAG, "Exception notifying emergency contact: " + e);
         }
         return null;
     }
+
+    /**
+     * Notifies the provider that emergency services were contacted by the user.
+     */
+    private void notifyEmergencyContact(Context context) {
+        try {
+            Rlog.i("notifyEmergencyContact; caller=%s", context.getOpPackageName());
+            context.getContentResolver().call(
+                    BlockedNumberContract.AUTHORITY_URI,
+                    BlockedNumberContract.METHOD_NOTIFY_EMERGENCY_CONTACT,
+                    null, null);
+        } catch (NullPointerException | IllegalArgumentException ex) {
+            // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+            // either of these happen.
+            Rlog.w(null, "notifyEmergencyContact: provider not ready.");
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index f0c6262..b7eeaf4 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -17,7 +17,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
@@ -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;
@@ -140,6 +141,7 @@
     protected Registrant mCatCcAlphaRegistrant;
     @UnsupportedAppUsage
     protected Registrant mSsRegistrant;
+    protected Registrant mRegistrationFailedRegistrant;
 
     // Preferred network type received from PhoneFactory.
     // This is used when establishing a connection to the
@@ -559,6 +561,16 @@
     }
 
     @Override
+    public void setOnRegistrationFailed(Handler h, int what, Object obj) {
+        mRegistrationFailedRegistrant = new Registrant(h, what, obj);
+    }
+
+    @Override
+    public void unSetOnRegistrationFailed(Handler h) {
+        mRegistrationFailedRegistrant.clear();
+    }
+
+    @Override
     public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj) {
         mVoicePrivacyOnRegistrants.addUnique(h, what, obj);
     }
@@ -754,7 +766,6 @@
 
     @Override
     public void registerForNetworkScanResult(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
         mRilNetworkScanResultRegistrants.addUnique(h, what, obj);
     }
 
@@ -953,7 +964,7 @@
 
     @Override
     public void registerForModemReset(Handler h, int what, Object obj) {
-        mModemResetRegistrants.add(new Registrant(h, what, obj));
+        mModemResetRegistrants.addUnique(h, what, obj);
     }
 
     @Override
@@ -963,7 +974,7 @@
 
     @Override
     public void registerForPcoData(Handler h, int what, Object obj) {
-        mPcoDataRegistrants.add(new Registrant(h, what, obj));
+        mPcoDataRegistrants.addUnique(h, what, obj);
     }
 
     @Override
@@ -973,7 +984,7 @@
 
     @Override
     public void registerForCarrierInfoForImsiEncryption(Handler h, int what, Object obj) {
-        mCarrierInfoForImsiEncryptionRegistrants.add(new Registrant(h, what, obj));
+        mCarrierInfoForImsiEncryptionRegistrants.addUnique(h, what, obj);
     }
 
     @Override
@@ -983,8 +994,6 @@
 
     @Override
     public void registerForNattKeepaliveStatus(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-
         synchronized (mStateMonitor) {
             mNattKeepaliveStatusRegistrants.addUnique(h, what, obj);
         }
@@ -996,4 +1005,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/BlockChecker.java b/src/java/com/android/internal/telephony/BlockChecker.java
index 1a63db6..f6b6356 100644
--- a/src/java/com/android/internal/telephony/BlockChecker.java
+++ b/src/java/com/android/internal/telephony/BlockChecker.java
@@ -3,7 +3,8 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.provider.BlockedNumberContract;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 /**
  * {@hide} Checks for blocked phone numbers against {@link BlockedNumberContract}
@@ -67,19 +68,76 @@
         long startTimeNano = System.nanoTime();
 
         try {
-            blockStatus = BlockedNumberContract.SystemContract.shouldSystemBlockNumber(
-                    context, phoneNumber, extras);
+            blockStatus = shouldSystemBlockNumber(context, phoneNumber, extras);
             if (blockStatus != BlockedNumberContract.STATUS_NOT_BLOCKED) {
                 Rlog.d(TAG, phoneNumber + " is blocked.");
             }
         } catch (Exception e) {
             Rlog.e(TAG, "Exception checking for blocked number: " + e);
         }
-
         int durationMillis = (int) ((System.nanoTime() - startTimeNano) / 1000000);
         if (durationMillis > 500 || VDBG) {
             Rlog.d(TAG, "Blocked number lookup took: " + durationMillis + " ms.");
         }
         return blockStatus;
     }
+
+    /**
+     * Returns {@code true} if {@code phoneNumber} is blocked taking
+     * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services
+     * have not been contacted recently and enhanced call blocking not been enabled, this
+     * method is equivalent to {@link #isBlocked(Context, String)}.
+     *
+     * @param context the context of the caller.
+     * @param phoneNumber the number to check.
+     * @param extras the extra attribute of the number.
+     * @return result code indicating if the number should be blocked, and if so why.
+     *         Valid values are: {@link #STATUS_NOT_BLOCKED}, {@link #STATUS_BLOCKED_IN_LIST},
+     *         {@link #STATUS_BLOCKED_NOT_IN_CONTACTS}, {@link #STATUS_BLOCKED_PAYPHONE},
+     *         {@link #STATUS_BLOCKED_RESTRICTED}, {@link #STATUS_BLOCKED_UNKNOWN_NUMBER}.
+     */
+    private static int shouldSystemBlockNumber(Context context, String phoneNumber,
+                                              Bundle extras) {
+        try {
+            String caller = context.getOpPackageName();
+            final Bundle res = context.getContentResolver().call(
+                    BlockedNumberContract.AUTHORITY_URI,
+                    BlockedNumberContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER,
+                    phoneNumber, extras);
+            int blockResult = res != null ? res.getInt(BlockedNumberContract.RES_BLOCK_STATUS,
+                    BlockedNumberContract.STATUS_NOT_BLOCKED) :
+                    BlockedNumberContract.STATUS_NOT_BLOCKED;
+            Rlog.d(TAG, "shouldSystemBlockNumber: number=" + Rlog.pii(TAG, phoneNumber)
+                    + "caller=" + caller + "result=" + blockStatusToString(blockResult));
+            return blockResult;
+        } catch (NullPointerException | IllegalArgumentException ex) {
+            // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if
+            // either of these happen.
+            Rlog.w(null, "shouldSystemBlockNumber: provider not ready.");
+            return BlockedNumberContract.STATUS_NOT_BLOCKED;
+        }
+    }
+
+    /**
+     * Converts a block status constant to a string equivalent for logging.
+     * @hide
+     */
+    private static String blockStatusToString(int blockStatus) {
+        switch (blockStatus) {
+            case BlockedNumberContract.STATUS_NOT_BLOCKED:
+                return "not blocked";
+            case BlockedNumberContract.STATUS_BLOCKED_IN_LIST:
+                return "blocked - in list";
+            case BlockedNumberContract.STATUS_BLOCKED_RESTRICTED:
+                return "blocked - restricted";
+            case BlockedNumberContract.STATUS_BLOCKED_UNKNOWN_NUMBER:
+                return "blocked - unknown";
+            case BlockedNumberContract.STATUS_BLOCKED_PAYPHONE:
+                return "blocked - payphone";
+            case BlockedNumberContract.STATUS_BLOCKED_NOT_IN_CONTACTS:
+                return "blocked - not in contacts";
+        }
+        return "unknown";
+    }
+
 }
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/Call.java b/src/java/com/android/internal/telephony/Call.java
index a9d1bd5..d3cb584 100644
--- a/src/java/com/android/internal/telephony/Call.java
+++ b/src/java/com/android/internal/telephony/Call.java
@@ -16,13 +16,13 @@
 
 package com.android.internal.telephony;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import com.android.ims.internal.ConferenceParticipant;
+import com.android.telephony.Rlog;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * {@hide}
@@ -110,6 +110,8 @@
     @UnsupportedAppUsage
     public abstract void hangup() throws CallStateException;
 
+    public abstract void hangup(@android.telecom.Call.RejectReason int rejectReason)
+            throws CallStateException;
 
     /**
      * hasConnection
diff --git a/src/java/com/android/internal/telephony/CallFailCause.java b/src/java/com/android/internal/telephony/CallFailCause.java
index 6e4e01c..6a36197 100644
--- a/src/java/com/android/internal/telephony/CallFailCause.java
+++ b/src/java/com/android/internal/telephony/CallFailCause.java
@@ -149,9 +149,43 @@
     int DIAL_MODIFIED_TO_SS   = 245;
     int DIAL_MODIFIED_TO_DIAL = 246;
 
+    // The call cannot be established because RADIO is OFF
+    int RADIO_OFF = 247;
+
+    // The call cannot be established because of no valid SIM
+    int NO_VALID_SIM = 249;
+
+    // The call is dropped or failed internally by modem
+    int RADIO_INTERNAL_ERROR = 250;
+
+    // Call failed because of UE timer expired while waiting for a response from network
+    int NETWORK_RESP_TIMEOUT = 251;
+
+    // Call failed because of a network reject
+    int NETWORK_REJECT                                   = 252;
+    // Call failed because of radio access failure. ex. RACH failure
+    int RADIO_ACCESS_FAILURE                             = 253;
+    // Call failed/dropped because of a Radio Link Failure (RLF).
+    int RADIO_LINK_FAILURE                               = 254;
+    // Call failed/dropped because of radio link lost
+    int RADIO_LINK_LOST                                  = 255;
+    // Call failed because of a radio uplink issue
+    int RADIO_UPLINK_FAILURE                             = 256;
+    // Call failed because of a RRC (Radio Resource Control) connection setup failure
+    int RADIO_SETUP_FAILURE                              = 257;
+    // Call failed/dropped because of RRC (Radio Resource Control) connection release from NW
+    int RADIO_RELEASE_NORMAL                             = 258;
+    /**
+     * Call failed/dropped because of RRC (Radio Resource Control) abnormally released by
+     * modem/network.
+     */
+    int RADIO_RELEASE_ABNORMAL                           = 259;
     //Access class blocked - TS 31.121 5.2.1
     int ACCESS_CLASS_BLOCKED = 260;
 
+    /** Call failed/dropped because of a network detach. */
+    int NETWORK_DETACH                                   = 261;
+
     //Emergency Redial
     int EMERGENCY_TEMP_FAILURE = 325;
     int EMERGENCY_PERM_FAILURE = 326;
@@ -171,6 +205,260 @@
     // Access Blocked by CDMA Network.
     int CDMA_ACCESS_BLOCKED            = 1009;
 
+    /** Mapped from ImsReasonInfo */
+    // The passed argument is an invalid
+    int LOCAL_ILLEGAL_ARGUMENT                           = 1200;
+    // The operation is invoked in invalid call state
+    int LOCAL_ILLEGAL_STATE                              = 1201;
+    // IMS service internal error
+    int LOCAL_INTERNAL_ERROR                             = 1202;
+    // IMS service goes down (service connection is lost)
+    int LOCAL_IMS_SERVICE_DOWN                           = 1203;
+    // No pending incoming call exists
+    int LOCAL_NO_PENDING_CALL                            = 1204;
+    // Service unavailable; by power off
+    int LOCAL_POWER_OFF                                  = 1205;
+    // Service unavailable; by low battery
+    int LOCAL_LOW_BATTERY                                = 1206;
+    // Service unavailable; by out of service (data service state)
+    int LOCAL_NETWORK_NO_SERVICE                         = 1207;
+
+    /* Service unavailable; by no LTE coverage
+     * (VoLTE is not supported even though IMS is registered)
+     */
+    int LOCAL_NETWORK_NO_LTE_COVERAGE                    = 1208;
+    // Service unavailable; by located in roaming area
+    int LOCAL_NETWORK_ROAMING                            = 1209;
+    // Service unavailable; by IP changed
+    int LOCAL_NETWORK_IP_CHANGED                         = 1210;
+    // Service unavailable; other
+    int LOCAL_SERVICE_UNAVAILABLE                        = 1211;
+    // Service unavailable; IMS connection is lost (IMS is not registered)
+    int LOCAL_NOT_REGISTERED                             = 1212;
+    // Max call exceeded
+    int LOCAL_MAX_CALL_EXCEEDED                          = 1213;
+    // Call decline
+    int LOCAL_CALL_DECLINE                               = 1214;
+    // SRVCC is in progress
+    int LOCAL_CALL_VCC_ON_PROGRESSING                    = 1215;
+    // Resource reservation is failed (QoS precondition)
+    int LOCAL_CALL_RESOURCE_RESERVATION_FAILED           = 1216;
+    /** Retry CS call; VoLTE service can't be provided by the network or remote end
+     *  Resolve the extra code(EXTRA_CODE_CALL_RETRY_*) if the below code is set
+     */
+    int LOCAL_CALL_CS_RETRY_REQUIRED                     = 1217;
+    // Retry VoLTE call; VoLTE service can't be provided by the network temporarily
+    int LOCAL_CALL_VOLTE_RETRY_REQUIRED                  = 1218;
+    // IMS call is already terminated (in TERMINATED state)
+    int LOCAL_CALL_TERMINATED                            = 1219;
+    // Handover not feasible
+    int LOCAL_HO_NOT_FEASIBLE                            = 1220;
+
+    // 1xx waiting timer is expired after sending INVITE request (MO only)
+    int TIMEOUT_1XX_WAITING                              = 1221;
+    /** User no answer during call setup operation (MO/MT)
+     *  MO : 200 OK to INVITE request is not received,
+     *  MT : No action from user after alerting the call
+     */
+    int TIMEOUT_NO_ANSWER                                = 1222;
+    /** User no answer during call update operation (MO/MT)
+     *  MO : 200 OK to re-INVITE request is not received,
+     *  MT : No action from user after alerting the call
+     */
+    int TIMEOUT_NO_ANSWER_CALL_UPDATE                    = 1223;
+
+    /**
+     * STATUSCODE (SIP response code) (IMS -> Telephony)
+     */
+    // SIP request is redirected
+    int SIP_REDIRECTED                                   = 1300;
+    /** 4xx responses */
+    // 400 : Bad Request
+    int SIP_BAD_REQUEST                                  = 1310;
+    // 403 : Forbidden
+    int SIP_FORBIDDEN                                    = 1311;
+    // 404 : Not Found
+    int SIP_NOT_FOUND                                    = 1312;
+    /** 415 : Unsupported Media Type
+     *  416 : Unsupported URI Scheme
+     *  420 : Bad Extension
+     */
+    int SIP_NOT_SUPPORTED                                = 1313;
+    // 408 : Request Timeout
+    int SIP_REQUEST_TIMEOUT                              = 1314;
+    // 480 : Temporarily Unavailable
+    int SIP_TEMPRARILY_UNAVAILABLE                       = 1315;
+    // 484 : Address Incomplete
+    int SIP_BAD_ADDRESS                                  = 1316;
+    /** 486 : Busy Here
+     *  600 : Busy Everywhere
+     */
+    int SIP_BUSY                                         = 1317;
+    // 487 : Request Terminated
+    int SIP_REQUEST_CANCELLED                            = 1318;
+    /** 406 : Not Acceptable
+     *  488 : Not Acceptable Here
+     *  606 : Not Acceptable
+     */
+    int SIP_NOT_ACCEPTABLE                               = 1319;
+    /** 410 : Gone
+     *  604 : Does Not Exist Anywhere
+     */
+    int SIP_NOT_REACHABLE                                = 1320;
+    // Others
+    int SIP_CLIENT_ERROR                                 = 1321;
+    // 481 : Transaction Does Not Exist
+    int SIP_TRANSACTION_DOES_NOT_EXIST                   = 1322;
+    /** 5xx responses
+     *  501 : Server Internal Error
+     */
+    int SIP_SERVER_INTERNAL_ERROR                        = 1330;
+    // 503 : Service Unavailable
+    int SIP_SERVICE_UNAVAILABLE                          = 1331;
+    // 504 : Server Time-out
+    int SIP_SERVER_TIMEOUT                               = 1332;
+    // Other
+    int SIP_SERVER_ERROR                                 = 1333;
+    /** 6xx responses
+     *  603 : Decline
+     */
+    int SIP_USER_REJECTED                                = 1340;
+    // Others
+    int SIP_GLOBAL_ERROR                                 = 1341;
+    // Emergency failure
+    int IMS_EMERGENCY_TEMP_FAILURE                       = 1342;
+    int IMS_EMERGENCY_PERM_FAILURE                       = 1343;
+    // Media resource initialization failed
+    int MEDIA_INIT_FAILED                                = 1400;
+    // RTP timeout (no audio / video traffic in the session)
+    int MEDIA_NO_DATA                                    = 1401;
+    // Media is not supported; so dropped the call
+    int MEDIA_NOT_ACCEPTABLE                             = 1402;
+    // Unknown media related errors
+    int MEDIA_UNSPECIFIED                                = 1403;
+    // User triggers the call end
+    int USER_TERMINATED                                  = 1500;
+    // No action while an incoming call is ringing
+    int USER_NOANSWER                                    = 1501;
+    // User ignores an incoming call
+    int USER_IGNORE                                      = 1502;
+    // User declines an incoming call
+    int USER_DECLINE                                     = 1503;
+    // Device declines/ends a call due to low battery
+    int LOW_BATTERY                                      = 1504;
+    // Device declines call due to blacklisted call ID
+    int BLACKLISTED_CALL_ID                              = 1505;
+    // The call is terminated by the network or remote user
+    int USER_TERMINATED_BY_REMOTE                        = 1510;
+
+    /**
+     * UT
+     */
+    int UT_NOT_SUPPORTED                                 = 1800;
+    int UT_SERVICE_UNAVAILABLE                           = 1801;
+    int UT_OPERATION_NOT_ALLOWED                         = 1802;
+    int UT_NETWORK_ERROR                                 = 1803;
+    int UT_CB_PASSWORD_MISMATCH                          = 1804;
+
+    /**
+     * ECBM
+     */
+    int ECBM_NOT_SUPPORTED                               = 1900;
+
+    /**
+     * Fail code used to indicate that Multi-endpoint is not supported by the Ims framework.
+     */
+    int MULTIENDPOINT_NOT_SUPPORTED                      = 1901;
+
+    /**
+     * CALL DROP error codes (Call could drop because of many reasons like Network not available,
+     *  handover, failed, etc)
+     */
+
+    /**
+     * CALL DROP error code for the case when a device is ePDG capable and when the user is on an
+     * active wifi call and at the edge of coverage and there is no qualified LTE network available
+     * to handover the call to. We get a handover NOT_TRIGERRED message from the modem. This error
+     * code is received as part of the handover message.
+     */
+    int CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE               = 2000;
+
+    // MT call has ended due to a release from the network because the call was answered elsewhere
+    int ANSWERED_ELSEWHERE                               = 2100;
+
+    // For MultiEndpoint - Call Pull request has failed
+    int CALL_PULL_OUT_OF_SYNC                            = 2101;
+
+    // For MultiEndpoint - Call has been pulled from primary to secondary
+    int CALL_PULLED                                      = 2102;
+
+    /**
+     * Supplementary services (HOLD/RESUME) failure error codes.
+     * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
+     */
+    int SUPP_SVC_FAILED                                  = 2300;
+    int SUPP_SVC_CANCELLED                               = 2301;
+    int SUPP_SVC_REINVITE_COLLISION                      = 2302;
+
+    //DPD Procedure received no response or send failed
+    int IWLAN_DPD_FAILURE                                = 2400;
+
+    // Establishment of the ePDG Tunnel Failed
+    int EPDG_TUNNEL_ESTABLISH_FAILURE                    = 2500;
+
+    // Re-keying of the ePDG Tunnel Failed; may not always result in teardown
+    int EPDG_TUNNEL_REKEY_FAILURE                        = 2501;
+
+    // Connection to the packet gateway is lost
+    int EPDG_TUNNEL_LOST_CONNECTION                      = 2502;
+
+    /**
+     * The maximum number of calls allowed has been reached.  Used in a multi-endpoint scenario
+     * where the number of calls across all connected devices has reached the maximum.
+     */
+    int MAXIMUM_NUMBER_OF_CALLS_REACHED                  = 2503;
+
+    /**
+     * Similar to {@link #CODE_LOCAL_CALL_DECLINE}, except indicates that a remote device has
+     * declined the call.  Used in a multi-endpoint scenario where a remote device declined an
+     * incoming call.
+     */
+    int REMOTE_CALL_DECLINE                              = 2504;
+
+    /**
+     * Indicates the call was disconnected due to the user reaching their data limit.
+     */
+    int DATA_LIMIT_REACHED                               = 2505;
+
+    /**
+     * Indicates the call was disconnected due to the user disabling cellular data.
+     */
+    int DATA_DISABLED                                    = 2506;
+
+    /**
+     * Indicates a call was disconnected due to loss of wifi signal.
+     */
+    int WIFI_LOST                                        = 2507;
+
+
+    /* OEM specific error codes. To be used by OEMs when they don't want to
+       reveal error code which would be replaced by ERROR_UNSPECIFIED */
+    int OEM_CAUSE_1                                      = 0xf001;
+    int OEM_CAUSE_2                                      = 0xf002;
+    int OEM_CAUSE_3                                      = 0xf003;
+    int OEM_CAUSE_4                                      = 0xf004;
+    int OEM_CAUSE_5                                      = 0xf005;
+    int OEM_CAUSE_6                                      = 0xf006;
+    int OEM_CAUSE_7                                      = 0xf007;
+    int OEM_CAUSE_8                                      = 0xf008;
+    int OEM_CAUSE_9                                      = 0xf009;
+    int OEM_CAUSE_10                                     = 0xf00a;
+    int OEM_CAUSE_11                                     = 0xf00b;
+    int OEM_CAUSE_12                                     = 0xf00c;
+    int OEM_CAUSE_13                                     = 0xf00d;
+    int OEM_CAUSE_14                                     = 0xf00e;
+    int OEM_CAUSE_15                                     = 0xf00f;
+
     int ERROR_UNSPECIFIED = 0xffff;
 
 }
diff --git a/src/java/com/android/internal/telephony/CallForwardInfo.java b/src/java/com/android/internal/telephony/CallForwardInfo.java
index 7d4f587..2a8319b 100644
--- a/src/java/com/android/internal/telephony/CallForwardInfo.java
+++ b/src/java/com/android/internal/telephony/CallForwardInfo.java
@@ -16,8 +16,9 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
+
+import com.android.telephony.Rlog;
 
 /**
  * See also RIL_CallForwardInfo in include/telephony/ril.h
diff --git a/src/java/com/android/internal/telephony/CallManager.java b/src/java/com/android/internal/telephony/CallManager.java
index 5112376..151a4bf 100644
--- a/src/java/com/android/internal/telephony/CallManager.java
+++ b/src/java/com/android/internal/telephony/CallManager.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
@@ -25,19 +25,16 @@
 import android.os.RegistrantList;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.sip.SipPhone;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
-
-
 /**
  * @hide
  *
diff --git a/src/java/com/android/internal/telephony/CallStateException.java b/src/java/com/android/internal/telephony/CallStateException.java
index 1356a2b..3fdc444 100644
--- a/src/java/com/android/internal/telephony/CallStateException.java
+++ b/src/java/com/android/internal/telephony/CallStateException.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/CallTracker.java b/src/java/com/android/internal/telephony/CallTracker.java
index f24b3c8..9e81bcc 100644
--- a/src/java/com/android/internal/telephony/CallTracker.java
+++ b/src/java/com/android/internal/telephony/CallTracker.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
diff --git a/src/java/com/android/internal/telephony/CarrierActionAgent.java b/src/java/com/android/internal/telephony/CarrierActionAgent.java
index c01c9d4..a87925d 100644
--- a/src/java/com/android/internal/telephony/CarrierActionAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierActionAgent.java
@@ -27,13 +27,13 @@
 import android.os.RegistrantList;
 import android.provider.Settings;
 import android.provider.Telephony;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.util.LocalLog;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -89,7 +89,7 @@
             final String action = intent.getAction();
             final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
             if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
-                if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+                if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
                     // ignore rebroadcast since carrier apps are direct boot aware.
                     return;
                 }
@@ -227,7 +227,7 @@
         carrierActionSetRadioEnabled(true);
         // notify configured carrier apps for reset
         mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
-                new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+                new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_RESET));
     }
 
     private RegistrantList getRegistrantsFromAction(int action) {
diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java
index f645746..a125fdf 100644
--- a/src/java/com/android/internal/telephony/CarrierInfoManager.java
+++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java
@@ -57,18 +57,16 @@
      *         used for encryption.
      */
     public static ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType,
-                                                                     Context context) {
+                                                                     Context context,
+                                                                     String operatorNumeric) {
         String mcc = "";
         String mnc = "";
-        final TelephonyManager telephonyManager =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        String simOperator = telephonyManager.getSimOperator();
-        if (!TextUtils.isEmpty(simOperator)) {
-            mcc = simOperator.substring(0, 3);
-            mnc = simOperator.substring(3);
+        if (!TextUtils.isEmpty(operatorNumeric)) {
+            mcc = operatorNumeric.substring(0, 3);
+            mnc = operatorNumeric.substring(3);
             Log.i(LOG_TAG, "using values for mnc, mcc: " + mnc + "," + mcc);
         } else {
-            Log.e(LOG_TAG, "Invalid networkOperator: " + simOperator);
+            Log.e(LOG_TAG, "Invalid networkOperator: " + operatorNumeric);
             return null;
         }
         Cursor findCursor = null;
diff --git a/src/java/com/android/internal/telephony/CarrierResolver.java b/src/java/com/android/internal/telephony/CarrierResolver.java
index 959522f..ea31a4b1 100644
--- a/src/java/com/android/internal/telephony/CarrierResolver.java
+++ b/src/java/com/android/internal/telephony/CarrierResolver.java
@@ -29,7 +29,6 @@
 import android.provider.Telephony;
 import android.service.carrier.CarrierIdentifier;
 import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -41,6 +40,7 @@
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
index 0393ffa..0b9cae1 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -34,6 +34,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.carrier.CarrierService;
+import android.telephony.PackageChangeReceiver;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -41,9 +42,8 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
-
 import com.android.internal.telephony.util.TelephonyUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
@@ -67,7 +67,10 @@
     public SparseArray<AppBinding> mBindings = new SparseArray();
     @VisibleForTesting
     public SparseArray<String> mLastSimState = new SparseArray<>();
-    private final PackageMonitor mPackageMonitor = new CarrierServicePackageMonitor();
+    private final PackageChangeReceiver mPackageMonitor = new CarrierServicePackageMonitor();
+
+    // whether we have successfully bound to the service
+    private boolean mServiceBound = false;
 
     private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
         @Override
@@ -86,12 +89,14 @@
     };
 
     private static final int EVENT_REBIND = 0;
-    private static final int EVENT_PERFORM_IMMEDIATE_UNBIND = 1;
+    @VisibleForTesting
+    public static final int EVENT_PERFORM_IMMEDIATE_UNBIND = 1;
     @VisibleForTesting
     public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 2;
 
     @UnsupportedAppUsage
-    private Handler mHandler = new Handler() {
+    @VisibleForTesting
+    public Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             int phoneId;
@@ -124,14 +129,20 @@
 
         updateBindingsAndSimStates();
 
-        PhoneConfigurationManager.getInstance().registerForMultiSimConfigChange(
+        PhoneConfigurationManager.registerForMultiSimConfigChange(
                 mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
 
         mPackageMonitor.register(
-                context, mHandler.getLooper(), UserHandle.ALL, false /* externalStorage */);
-        mContext.registerReceiverAsUser(mUserUnlockedReceiver, UserHandle.SYSTEM,
+                context, mHandler.getLooper(), UserHandle.ALL);
+        try {
+            Context contextAsUser = mContext.createPackageContextAsUser(mContext.getPackageName(),
+                0, UserHandle.SYSTEM);
+            contextAsUser.registerReceiver(mUserUnlockedReceiver,
                 new IntentFilter(Intent.ACTION_USER_UNLOCKED), null /* broadcastPermission */,
                 mHandler);
+        } catch (PackageManager.NameNotFoundException e) {
+            loge("Package name not found: " + e.getMessage());
+        }
     }
 
     // Create or dispose mBindings and mLastSimState objects.
@@ -266,9 +277,12 @@
 
             String error;
             try {
-                if (mContext.bindServiceAsUser(carrierService, connection,
-                        Context.BIND_AUTO_CREATE |  Context.BIND_FOREGROUND_SERVICE,
-                        mHandler, Process.myUserHandle())) {
+                if (mContext.createContextAsUser(Process.myUserHandle(), 0)
+                        .bindService(carrierService,
+                                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                                (r) -> mHandler.post(r),
+                                connection)) {
+                    mServiceBound = true;
                     return;
                 }
 
@@ -323,8 +337,13 @@
             carrierServiceClass = null;
 
             // Actually unbind
-            log("Unbinding from carrier app");
-            mContext.unbindService(connection);
+            if (mServiceBound) {
+                log("Unbinding from carrier app");
+                mServiceBound = false;
+                mContext.unbindService(connection);
+            } else {
+                log("Not bound, skipping unbindService call");
+            }
             connection = null;
             mUnbindScheduledUptimeMillis = -1;
         }
@@ -362,24 +381,36 @@
         }
 
         @Override
+        public void onBindingDied(ComponentName name) {
+            log("Binding from carrier app died: " + name.flattenToString());
+            connected = false;
+        }
+
+        @Override
+        public void onNullBinding(ComponentName name) {
+            log("Null binding from carrier app: " + name.flattenToString());
+            connected = false;
+        }
+
+        @Override
         public String toString() {
             return "CarrierServiceConnection[connected=" + connected + "]";
         }
     }
 
-    private class CarrierServicePackageMonitor extends PackageMonitor {
+    private class CarrierServicePackageMonitor extends PackageChangeReceiver {
         @Override
-        public void onPackageAdded(String packageName, int reason) {
+        public void onPackageAdded(String packageName) {
             evaluateBinding(packageName, true /* forceUnbind */);
         }
 
         @Override
-        public void onPackageRemoved(String packageName, int reason) {
+        public void onPackageRemoved(String packageName) {
             evaluateBinding(packageName, true /* forceUnbind */);
         }
 
         @Override
-        public void onPackageUpdateFinished(String packageName, int uid) {
+        public void onPackageUpdateFinished(String packageName) {
             evaluateBinding(packageName, true /* forceUnbind */);
         }
 
@@ -389,13 +420,12 @@
         }
 
         @Override
-        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+        public void onHandleForceStop(String[] packages, boolean doit) {
             if (doit) {
                 for (String packageName : packages) {
                     evaluateBinding(packageName, true /* forceUnbind */);
                 }
             }
-            return super.onHandleForceStop(intent, packages, uid, doit);
         }
 
         private void evaluateBinding(String carrierPackageName, boolean forceUnbind) {
@@ -424,6 +454,8 @@
         Log.d(LOG_TAG, message);
     }
 
+    private static void loge(String message) { Log.e(LOG_TAG, message); }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("CarrierServiceBindHelper:");
         for (int i = 0; i < mBindings.size(); i++) {
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index e112068..112daf5 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -30,19 +30,17 @@
 import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.util.NotificationChannelController;
+import com.android.telephony.Rlog;
 
 import java.util.HashMap;
 import java.util.Map;
 
-
-
 /**
  * This contains Carrier specific logic based on the states/events
  * managed in ServiceStateTracker.
@@ -166,15 +164,8 @@
         if (mSST.mSS == null) {
             return true; //something has gone wrong, return true and not show the notification.
         }
-        return (mSST.mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
-                || mSST.mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE);
-    }
-
-    private boolean isPhoneVoiceRegistered() {
-        if (mSST.mSS == null) {
-            return true; //something has gone wrong, return true and not show the notification.
-        }
-        return (mSST.mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+        return (mSST.mSS.getState() == ServiceState.STATE_IN_SERVICE
+                || mSST.mSS.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE);
     }
 
     private boolean isPhoneRegisteredForWifiCalling() {
@@ -456,8 +447,8 @@
     }
 
     /**
-     * Class that defines the emergency notification, which is shown when the user is out of cell
-     * connectivity, but has wifi enabled.
+     * Class that defines the emergency notification, which is shown when Wi-Fi Calling is
+     * available.
      */
     public class EmergencyNetworkNotification implements NotificationType {
 
@@ -502,10 +493,9 @@
          */
         public boolean sendMessage() {
             Rlog.i(LOG_TAG, "EmergencyNetworkNotification: sendMessage() w/values: "
-                    + "," + isPhoneVoiceRegistered() + "," + mDelay + ","
-                    + isPhoneRegisteredForWifiCalling() + "," + mSST.isRadioOn());
-            if (mDelay == UNINITIALIZED_DELAY_VALUE || isPhoneVoiceRegistered()
-                    || !isPhoneRegisteredForWifiCalling()) {
+                    + "," + mDelay + "," + isPhoneRegisteredForWifiCalling() + ","
+                    + mSST.isRadioOn());
+            if (mDelay == UNINITIALIZED_DELAY_VALUE || !isPhoneRegisteredForWifiCalling()) {
                 return false;
             }
             return true;
@@ -525,6 +515,7 @@
                     .setContentTitle(title)
                     .setStyle(new Notification.BigTextStyle().bigText(details))
                     .setContentText(details)
+                    .setFlag(Notification.FLAG_NO_CLEAR, true)
                     .setChannelId(NotificationChannelController.CHANNEL_ID_WFC);
         }
     }
diff --git a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
index 24e5059..cabb009 100644
--- a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
+++ b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
@@ -27,12 +27,12 @@
 import android.service.carrier.CarrierMessagingServiceWrapper;
 import android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper;
 import android.service.carrier.MessagePdu;
-import android.telephony.Rlog;
 import android.util.LocalLog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccController;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
index ad753db..8a728ad 100644
--- a/src/java/com/android/internal/telephony/CarrierSignalAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
@@ -15,6 +15,9 @@
  */
 package com.android.internal.telephony;
 
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
+
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -30,14 +33,15 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 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 com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -47,9 +51,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
-import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
-
 /**
  * This class act as an CarrierSignalling Agent.
  * it load registered carrier signalling receivers from carrier config, cache the result to avoid
@@ -98,11 +99,11 @@
      * This is a list of supported signals from CarrierSignalAgent
      */
     private final Set<String> mCarrierSignalList = new HashSet<>(Arrays.asList(
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE,
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED,
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET,
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE));
+            TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE,
+            TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED,
+            TelephonyManager.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+            TelephonyManager.ACTION_CARRIER_SIGNAL_RESET,
+            TelephonyManager.ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE));
 
     private final LocalLog mErrorLocalLog = new LocalLog(20);
 
@@ -148,10 +149,10 @@
                             // an optimization to avoid signaling on every default network switch.
                             if (!mDefaultNetworkAvail) {
                                 if (DBG) log("Default network available: " + network);
-                                Intent intent = new Intent(TelephonyIntents
+                                Intent intent = new Intent(TelephonyManager
                                         .ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE);
                                 intent.putExtra(
-                                        TelephonyIntents.EXTRA_DEFAULT_NETWORK_AVAILABLE_KEY, true);
+                                        TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, true);
                                 notifyCarrierSignalReceivers(intent);
                                 mDefaultNetworkAvail = true;
                             }
@@ -159,10 +160,10 @@
                         @Override
                         public void onLost(Network network) {
                             if (DBG) log("Default network lost: " + network);
-                            Intent intent = new Intent(TelephonyIntents
+                            Intent intent = new Intent(TelephonyManager
                                     .ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE);
                             intent.putExtra(
-                                    TelephonyIntents.EXTRA_DEFAULT_NETWORK_AVAILABLE_KEY, false);
+                                    TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, false);
                             notifyCarrierSignalReceivers(intent);
                             mDefaultNetworkAvail = false;
                         }
diff --git a/src/java/com/android/internal/telephony/CarrierSmsUtils.java b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
index a64aea7..f78d147 100644
--- a/src/java/com/android/internal/telephony/CarrierSmsUtils.java
+++ b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
@@ -24,7 +24,8 @@
 import android.os.Binder;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 import java.util.List;
 
diff --git a/src/java/com/android/internal/telephony/CellBroadcastHandler.java b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
deleted file mode 100644
index 08be268..0000000
--- a/src/java/com/android/internal/telephony/CellBroadcastHandler.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright (C) 2013 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 android.content.PermissionChecker.PERMISSION_GRANTED;
-import static android.provider.Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.AppOpsManager;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.PermissionChecker;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Telephony;
-import android.provider.Telephony.CellBroadcasts;
-import android.telephony.SmsCbMessage;
-import android.telephony.SubscriptionManager;
-import android.text.format.DateUtils;
-import android.util.LocalLog;
-import android.util.Log;
-
-import com.android.internal.telephony.CbGeoUtils.Geometry;
-import com.android.internal.telephony.CbGeoUtils.LatLng;
-import com.android.internal.telephony.metrics.TelephonyMetrics;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Dispatch new Cell Broadcasts to receivers. Acquires a private wakelock until the broadcast
- * completes and our result receiver is called.
- */
-public class CellBroadcastHandler extends WakeLockStateMachine {
-    private static final String EXTRA_MESSAGE = "message";
-
-    private final LocalLog mLocalLog = new LocalLog(100);
-
-    protected static final Uri CELL_BROADCAST_URI = Uri.parse("content://cellbroadcasts");
-
-    /** Uses to request the location update. */
-    public final LocationRequester mLocationRequester;
-
-    private CellBroadcastHandler(Context context, Phone phone) {
-        this("CellBroadcastHandler", context, phone);
-    }
-
-    protected CellBroadcastHandler(String debugTag, Context context, Phone phone) {
-        super(debugTag, context, phone);
-        mLocationRequester = new LocationRequester(
-                context,
-                (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE),
-                getHandler().getLooper());
-    }
-
-    /**
-     * Create a new CellBroadcastHandler.
-     * @param context the context to use for dispatching Intents
-     * @return the new handler
-     */
-    public static CellBroadcastHandler makeCellBroadcastHandler(Context context, Phone phone) {
-        CellBroadcastHandler handler = new CellBroadcastHandler(context, phone);
-        handler.start();
-        return handler;
-    }
-
-    /**
-     * Handle Cell Broadcast messages from {@code CdmaInboundSmsHandler}.
-     * 3GPP-format Cell Broadcast messages sent from radio are handled in the subclass.
-     *
-     * @param message the message to process
-     * @return true if need to wait for geo-fencing or an ordered broadcast was sent.
-     */
-    @Override
-    protected boolean handleSmsMessage(Message message) {
-        if (message.obj instanceof SmsCbMessage) {
-            handleBroadcastSms((SmsCbMessage) message.obj);
-            return true;
-        } else {
-            loge("handleMessage got object of type: " + message.obj.getClass().getName());
-            return false;
-        }
-    }
-
-    /**
-     * Dispatch a Cell Broadcast message to listeners.
-     * @param message the Cell Broadcast to broadcast
-     */
-    protected void handleBroadcastSms(SmsCbMessage message) {
-        // Log Cellbroadcast msg received event
-        TelephonyMetrics metrics = TelephonyMetrics.getInstance();
-        metrics.writeNewCBSms(mPhone.getPhoneId(), message.getMessageFormat(),
-                message.getMessagePriority(), message.isCmasMessage(), message.isEtwsMessage(),
-                message.getServiceCategory(), message.getSerialNumber(),
-                System.currentTimeMillis());
-
-        // TODO: Database inserting can be time consuming, therefore this should be changed to
-        // asynchronous.
-        ContentValues cv = message.getContentValues();
-        Uri uri = mContext.getContentResolver().insert(CELL_BROADCAST_URI, cv);
-
-        if (message.needGeoFencingCheck()) {
-            if (DBG) {
-                log("Request location update for geo-fencing. serialNumber = "
-                        + message.getSerialNumber());
-            }
-
-            requestLocationUpdate(location -> {
-                if (location == null) {
-                    // Broadcast the message directly if the location is not available.
-                    broadcastMessage(message, uri);
-                } else {
-                    performGeoFencing(message, uri, message.getGeometries(), location);
-                }
-            }, message.getMaximumWaitingTime());
-        } else {
-            if (DBG) {
-                log("Broadcast the message directly because no geo-fencing required, "
-                        + "serialNumber = " + message.getSerialNumber()
-                        + " needGeoFencing = " + message.needGeoFencingCheck());
-            }
-            broadcastMessage(message, uri);
-        }
-    }
-
-    /**
-     * Perform a geo-fencing check for {@code message}. Broadcast the {@code message} if the
-     * {@code location} is inside the {@code broadcastArea}.
-     * @param message the message need to geo-fencing check
-     * @param uri the message's uri
-     * @param broadcastArea the broadcast area of the message
-     * @param location current location
-     */
-    protected void performGeoFencing(SmsCbMessage message, Uri uri, List<Geometry> broadcastArea,
-            LatLng location) {
-
-        if (DBG) {
-            logd("Perform geo-fencing check for message identifier = "
-                    + message.getServiceCategory()
-                    + " serialNumber = " + message.getSerialNumber());
-        }
-
-        for (Geometry geo : broadcastArea) {
-            if (geo.contains(location)) {
-                broadcastMessage(message, uri);
-                return;
-            }
-        }
-
-        if (DBG) {
-            logd("Device location is outside the broadcast area "
-                    + CbGeoUtils.encodeGeometriesToString(broadcastArea));
-        }
-
-        sendMessage(EVENT_BROADCAST_NOT_REQUIRED);
-    }
-
-    /**
-     * Request a single location update.
-     * @param callback a callback will be called when the location is available.
-     * @param maximumWaitTimeSec the maximum wait time of this request. If location is not updated
-     * within the maximum wait time, {@code callback#onLocationUpadte(null)} will be called.
-     */
-    protected void requestLocationUpdate(LocationUpdateCallback callback, int maximumWaitTimeSec) {
-        mLocationRequester.requestLocationUpdate(callback, maximumWaitTimeSec);
-    }
-
-    /**
-     * Broadcast a list of cell broadcast messages.
-     * @param cbMessages a list of cell broadcast message.
-     * @param cbMessageUris the corresponding {@link Uri} of the cell broadcast messages.
-     */
-    protected void broadcastMessage(List<SmsCbMessage> cbMessages, List<Uri> cbMessageUris) {
-        for (int i = 0; i < cbMessages.size(); i++) {
-            broadcastMessage(cbMessages.get(i), cbMessageUris.get(i));
-        }
-    }
-
-    /**
-     * Broadcast the {@code message} to the applications.
-     * @param message a message need to broadcast
-     * @param messageUri message's uri
-     */
-    protected void broadcastMessage(@NonNull SmsCbMessage message, @Nullable Uri messageUri) {
-        String receiverPermission;
-        int appOp;
-        String msg;
-        Intent intent;
-        if (message.isEmergencyMessage()) {
-            msg = "Dispatching emergency SMS CB, SmsCbMessage is: " + message;
-            log(msg);
-            mLocalLog.log(msg);
-            intent = new Intent(Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION);
-            //Emergency alerts need to be delivered with high priority
-            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-            receiverPermission = Manifest.permission.RECEIVE_EMERGENCY_BROADCAST;
-            appOp = AppOpsManager.OP_RECEIVE_EMERGECY_SMS;
-
-            intent.putExtra(EXTRA_MESSAGE, message);
-            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
-
-            if (Build.IS_DEBUGGABLE) {
-                // Send additional broadcast intent to the specified package. This is only for sl4a
-                // automation tests.
-                final String additionalPackage = Settings.Secure.getString(
-                        mContext.getContentResolver(), CMAS_ADDITIONAL_BROADCAST_PKG);
-                if (additionalPackage != null) {
-                    Intent additionalIntent = new Intent(intent);
-                    additionalIntent.setPackage(additionalPackage);
-                    mContext.sendOrderedBroadcastAsUser(additionalIntent, UserHandle.ALL,
-                            receiverPermission, appOp, null, getHandler(), Activity.RESULT_OK,
-                            null, null);
-                }
-            }
-
-            String[] pkgs = mContext.getResources().getStringArray(
-                    com.android.internal.R.array.config_defaultCellBroadcastReceiverPkgs);
-            mReceiverCount.addAndGet(pkgs.length);
-            for (String pkg : pkgs) {
-                // Explicitly send the intent to all the configured cell broadcast receivers.
-                intent.setPackage(pkg);
-                mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, receiverPermission,
-                        appOp, mReceiver, getHandler(), Activity.RESULT_OK, null, null);
-            }
-        } else {
-            msg = "Dispatching SMS CB, SmsCbMessage is: " + message;
-            log(msg);
-            mLocalLog.log(msg);
-            intent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
-            // Send implicit intent since there are various 3rd party carrier apps listen to
-            // this intent.
-            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-            receiverPermission = Manifest.permission.RECEIVE_SMS;
-            appOp = AppOpsManager.OP_RECEIVE_SMS;
-
-            intent.putExtra(EXTRA_MESSAGE, message);
-            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
-
-            mReceiverCount.incrementAndGet();
-            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, receiverPermission, appOp,
-                    mReceiver, getHandler(), Activity.RESULT_OK, null, null);
-        }
-
-        if (messageUri != null) {
-            ContentValues cv = new ContentValues();
-            cv.put(CellBroadcasts.MESSAGE_BROADCASTED, 1);
-            mContext.getContentResolver().update(CELL_BROADCAST_URI, cv,
-                    CellBroadcasts._ID + "=?", new String[] {messageUri.getLastPathSegment()});
-        }
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("CellBroadcastHandler:");
-        mLocalLog.dump(fd, pw, args);
-        pw.flush();
-    }
-
-    /** The callback interface of a location request. */
-    public interface LocationUpdateCallback {
-        /**
-         * Call when the location update is available.
-         * @param location a location in (latitude, longitude) format, or {@code null} if the
-         * location service is not available.
-         */
-        void onLocationUpdate(@Nullable LatLng location);
-    }
-
-    private static final class LocationRequester {
-        private static final String TAG = LocationRequester.class.getSimpleName();
-
-        /**
-         * Use as the default maximum wait time if the cell broadcast doesn't specify the value.
-         * Most of the location request should be responded within 20 seconds.
-         */
-        private static final int DEFAULT_MAXIMUM_WAIT_TIME_SEC = 20;
-
-        /**
-         * Trigger this event when the {@link LocationManager} is not responded within the given
-         * time.
-         */
-        private static final int EVENT_LOCATION_REQUEST_TIMEOUT = 1;
-
-        /** Request a single location update. */
-        private static final int EVENT_REQUEST_LOCATION_UPDATE = 2;
-
-        /**
-         * Request location update from network or gps location provider. Network provider will be
-         * used if available, otherwise use the gps provider.
-         */
-        private static final List<String> LOCATION_PROVIDERS = Arrays.asList(
-                LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER);
-
-        private final LocationManager mLocationManager;
-        private final Looper mLooper;
-        private final List<LocationUpdateCallback> mCallbacks;
-        private final Context mContext;
-        private Handler mLocationHandler;
-
-        LocationRequester(Context context, LocationManager locationManager, Looper looper) {
-            mLocationManager = locationManager;
-            mLooper = looper;
-            mCallbacks = new ArrayList<>();
-            mContext = context;
-            mLocationHandler = new LocationHandler(looper);
-        }
-
-        /**
-         * Request a single location update. If the location is not available, a callback with
-         * {@code null} location will be called immediately.
-         *
-         * @param callback a callback to the the response when the location is available
-         * @param maximumWaitTimeSec the maximum wait time of this request. If location is not
-         * updated within the maximum wait time, {@code callback#onLocationUpadte(null)} will be
-         * called.
-         */
-        void requestLocationUpdate(@NonNull LocationUpdateCallback callback,
-                int maximumWaitTimeSec) {
-            mLocationHandler.obtainMessage(EVENT_REQUEST_LOCATION_UPDATE, maximumWaitTimeSec,
-                    0 /* arg2 */, callback).sendToTarget();
-        }
-
-        private void onLocationUpdate(@Nullable LatLng location) {
-            for (LocationUpdateCallback callback : mCallbacks) {
-                callback.onLocationUpdate(location);
-            }
-            mCallbacks.clear();
-        }
-
-        private void requestLocationUpdateInternal(@NonNull LocationUpdateCallback callback,
-                int maximumWaitTimeSec) {
-            if (DBG) Log.d(TAG, "requestLocationUpdate");
-            if (!isLocationServiceAvailable()) {
-                if (DBG) {
-                    Log.d(TAG, "Can't request location update because of no location permission");
-                }
-                callback.onLocationUpdate(null);
-                return;
-            }
-
-            if (!mLocationHandler.hasMessages(EVENT_LOCATION_REQUEST_TIMEOUT)) {
-                if (maximumWaitTimeSec == SmsCbMessage.MAXIMUM_WAIT_TIME_NOT_SET) {
-                    maximumWaitTimeSec = DEFAULT_MAXIMUM_WAIT_TIME_SEC;
-                }
-                mLocationHandler.sendMessageDelayed(
-                        mLocationHandler.obtainMessage(EVENT_LOCATION_REQUEST_TIMEOUT),
-                        maximumWaitTimeSec * DateUtils.SECOND_IN_MILLIS);
-            }
-
-            mCallbacks.add(callback);
-
-            for (String provider : LOCATION_PROVIDERS) {
-                if (mLocationManager.isProviderEnabled(provider)) {
-                    mLocationManager.requestSingleUpdate(provider, mLocationListener, mLooper);
-                    break;
-                }
-            }
-        }
-
-        private boolean isLocationServiceAvailable() {
-            if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)
-                    && !hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION)) return false;
-            for (String provider : LOCATION_PROVIDERS) {
-                if (mLocationManager.isProviderEnabled(provider)) return true;
-            }
-            return false;
-        }
-
-        private boolean hasPermission(String permission) {
-            return PermissionChecker.checkCallingOrSelfPermissionForDataDelivery(mContext, permission)
-                    == PERMISSION_GRANTED;
-        }
-
-        private final LocationListener mLocationListener = new LocationListener() {
-            @Override
-            public void onLocationChanged(Location location) {
-                mLocationHandler.removeMessages(EVENT_LOCATION_REQUEST_TIMEOUT);
-                onLocationUpdate(new LatLng(location.getLatitude(), location.getLongitude()));
-            }
-
-            @Override
-            public void onStatusChanged(String provider, int status, Bundle extras) {}
-
-            @Override
-            public void onProviderEnabled(String provider) {}
-
-            @Override
-            public void onProviderDisabled(String provider) {}
-        };
-
-        private final class LocationHandler extends Handler {
-            LocationHandler(Looper looper) {
-                super(looper);
-            }
-
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case EVENT_LOCATION_REQUEST_TIMEOUT:
-                        if (DBG) Log.d(TAG, "location request timeout");
-                        onLocationUpdate(null);
-                        break;
-                    case EVENT_REQUEST_LOCATION_UPDATE:
-                        requestLocationUpdateInternal((LocationUpdateCallback) msg.obj, msg.arg1);
-                        break;
-                    default:
-                        Log.e(TAG, "Unsupported message type " + msg.what);
-                }
-            }
-        }
-    }
-}
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/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index b45d63d..4971643 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony;
 
-import android.hardware.radio.V1_0.CellInfoType;
 import android.hardware.radio.V1_0.RegState;
 import android.hardware.radio.V1_4.DataRegStateResult.VopsInfo.hidl_discriminator;
 import android.os.AsyncResult;
@@ -27,20 +26,16 @@
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.CellIdentity;
-import android.telephony.CellIdentityCdma;
-import android.telephony.CellIdentityGsm;
-import android.telephony.CellIdentityLte;
-import android.telephony.CellIdentityTdscdma;
-import android.telephony.CellIdentityWcdma;
 import android.telephony.LteVopsSupportInfo;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.NetworkService;
 import android.telephony.NetworkServiceCallback;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
+import com.android.telephony.Rlog;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
@@ -228,8 +223,7 @@
                 int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
                 List<Integer> availableServices = getAvailableServices(
                         regState, domain, emergencyOnly);
-                CellIdentity cellIdentity =
-                        convertHalCellIdentityToCellIdentity(voiceRegState.cellIdentity);
+                CellIdentity cellIdentity = CellIdentity.create(voiceRegState.cellIdentity);
 
                 return new NetworkRegistrationInfo(domain, transportType, regState,
                         networkType, reasonForDenial, emergencyOnly, availableServices,
@@ -251,8 +245,7 @@
                 int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
                 List<Integer> availableServices = getAvailableServices(
                         regState, domain, emergencyOnly);
-                CellIdentity cellIdentity =
-                        convertHalCellIdentityToCellIdentity(voiceRegState.cellIdentity);
+                CellIdentity cellIdentity = CellIdentity.create(voiceRegState.cellIdentity);
 
                 return new NetworkRegistrationInfo(domain, transportType, regState,
                         networkType, reasonForDenial, emergencyOnly, availableServices,
@@ -289,8 +282,7 @@
                 reasonForDenial = dataRegState.reasonDataDenied;
                 emergencyOnly = isEmergencyOnly(dataRegState.regState);
                 maxDataCalls = dataRegState.maxDataCalls;
-
-                cellIdentity = convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
+                cellIdentity = CellIdentity.create(dataRegState.cellIdentity);
             } else if (result instanceof android.hardware.radio.V1_2.DataRegStateResult) {
                 android.hardware.radio.V1_2.DataRegStateResult dataRegState =
                         (android.hardware.radio.V1_2.DataRegStateResult) result;
@@ -299,7 +291,7 @@
                 reasonForDenial = dataRegState.reasonDataDenied;
                 emergencyOnly = isEmergencyOnly(dataRegState.regState);
                 maxDataCalls = dataRegState.maxDataCalls;
-                cellIdentity = convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
+                cellIdentity = CellIdentity.create(dataRegState.cellIdentity);
             } else if (result instanceof android.hardware.radio.V1_4.DataRegStateResult) {
                 android.hardware.radio.V1_4.DataRegStateResult dataRegState =
                         (android.hardware.radio.V1_4.DataRegStateResult) result;
@@ -309,7 +301,7 @@
                 reasonForDenial = dataRegState.base.reasonDataDenied;
                 emergencyOnly = isEmergencyOnly(dataRegState.base.regState);
                 maxDataCalls = dataRegState.base.maxDataCalls;
-                cellIdentity = convertHalCellIdentityToCellIdentity(dataRegState.base.cellIdentity);
+                cellIdentity = CellIdentity.create(dataRegState.base.cellIdentity);
                 android.hardware.radio.V1_4.NrIndicators nrIndicators = dataRegState.nrIndicators;
 
                 // Check for lteVopsInfo only if its initialized and RAT is EUTRAN
@@ -362,118 +354,6 @@
             return new LteVopsSupportInfo(vops, emergency);
         }
 
-        private CellIdentity convertHalCellIdentityToCellIdentity(
-                android.hardware.radio.V1_0.CellIdentity cellIdentity) {
-            if (cellIdentity == null) {
-                return null;
-            }
-
-            CellIdentity result = null;
-            switch(cellIdentity.cellInfoType) {
-                case CellInfoType.GSM: {
-                    if (cellIdentity.cellIdentityGsm.size() == 1) {
-                        android.hardware.radio.V1_0.CellIdentityGsm cellIdentityGsm =
-                                cellIdentity.cellIdentityGsm.get(0);
-                        result = new CellIdentityGsm(cellIdentityGsm);
-                    }
-                    break;
-                }
-                case CellInfoType.WCDMA: {
-                    if (cellIdentity.cellIdentityWcdma.size() == 1) {
-                        android.hardware.radio.V1_0.CellIdentityWcdma cellIdentityWcdma =
-                                cellIdentity.cellIdentityWcdma.get(0);
-                        result = new CellIdentityWcdma(cellIdentityWcdma);
-                    }
-                    break;
-                }
-                case CellInfoType.TD_SCDMA: {
-                    if (cellIdentity.cellIdentityTdscdma.size() == 1) {
-                        android.hardware.radio.V1_0.CellIdentityTdscdma cellIdentityTdscdma =
-                                cellIdentity.cellIdentityTdscdma.get(0);
-                        result = new  CellIdentityTdscdma(cellIdentityTdscdma);
-                    }
-                    break;
-                }
-                case CellInfoType.LTE: {
-                    if (cellIdentity.cellIdentityLte.size() == 1) {
-                        android.hardware.radio.V1_0.CellIdentityLte cellIdentityLte =
-                                cellIdentity.cellIdentityLte.get(0);
-                        result = new CellIdentityLte(cellIdentityLte);
-                    }
-                    break;
-                }
-                case CellInfoType.CDMA: {
-                    if (cellIdentity.cellIdentityCdma.size() == 1) {
-                        android.hardware.radio.V1_0.CellIdentityCdma cellIdentityCdma =
-                                cellIdentity.cellIdentityCdma.get(0);
-                        result = new CellIdentityCdma(cellIdentityCdma);
-                    }
-                    break;
-                }
-                case CellInfoType.NONE:
-                default:
-                    break;
-            }
-
-            return result;
-        }
-
-        private CellIdentity convertHalCellIdentityToCellIdentity(
-                android.hardware.radio.V1_2.CellIdentity cellIdentity) {
-            if (cellIdentity == null) {
-                return null;
-            }
-
-            CellIdentity result = null;
-            switch(cellIdentity.cellInfoType) {
-                case CellInfoType.GSM: {
-                    if (cellIdentity.cellIdentityGsm.size() == 1) {
-                        android.hardware.radio.V1_2.CellIdentityGsm cellIdentityGsm =
-                                cellIdentity.cellIdentityGsm.get(0);
-                        result = new CellIdentityGsm(cellIdentityGsm);
-                    }
-                    break;
-                }
-                case CellInfoType.WCDMA: {
-                    if (cellIdentity.cellIdentityWcdma.size() == 1) {
-                        android.hardware.radio.V1_2.CellIdentityWcdma cellIdentityWcdma =
-                                cellIdentity.cellIdentityWcdma.get(0);
-                        result = new CellIdentityWcdma(cellIdentityWcdma);
-                    }
-                    break;
-                }
-                case CellInfoType.TD_SCDMA: {
-                    if (cellIdentity.cellIdentityTdscdma.size() == 1) {
-                        android.hardware.radio.V1_2.CellIdentityTdscdma cellIdentityTdscdma =
-                                cellIdentity.cellIdentityTdscdma.get(0);
-                        result = new  CellIdentityTdscdma(cellIdentityTdscdma);
-                    }
-                    break;
-                }
-                case CellInfoType.LTE: {
-                    if (cellIdentity.cellIdentityLte.size() == 1) {
-                        android.hardware.radio.V1_2.CellIdentityLte cellIdentityLte =
-                                cellIdentity.cellIdentityLte.get(0);
-                        result = new CellIdentityLte(cellIdentityLte);
-                    }
-                    break;
-                }
-                case CellInfoType.CDMA: {
-                    if (cellIdentity.cellIdentityCdma.size() == 1) {
-                        android.hardware.radio.V1_2.CellIdentityCdma cellIdentityCdma =
-                                cellIdentity.cellIdentityCdma.get(0);
-                        result = new CellIdentityCdma(cellIdentityCdma);
-                    }
-                    break;
-                }
-                case CellInfoType.NONE:
-                default:
-                    break;
-            }
-
-            return result;
-        }
-
         @Override
         public void requestNetworkRegistrationInfo(int domain, NetworkServiceCallback callback) {
             if (DBG) log("requestNetworkRegistrationInfo for domain " + domain);
diff --git a/src/java/com/android/internal/telephony/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/CellularNetworkValidator.java
index 48a90ea..4b8e102 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkValidator.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkValidator.java
@@ -21,6 +21,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.Handler;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
@@ -101,7 +102,7 @@
      */
     public boolean isValidationFeatureSupported() {
         return PhoneConfigurationManager.getInstance().getCurrentPhoneCapability()
-                .validationBeforeSwitchSupported;
+                .getPsDataConnectionLingerTimeMillis() > 0;
     }
 
     @VisibleForTesting
@@ -193,7 +194,8 @@
         return new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                .setNetworkSpecifier(String.valueOf(mSubId))
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                        .setSubscriptionId(mSubId).build())
                 .build();
     }
 
diff --git a/src/java/com/android/internal/telephony/ClientWakelockAccountant.java b/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
index c47faab..a78b520 100644
--- a/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
+++ b/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
@@ -17,9 +17,10 @@
 package com.android.internal.telephony;
 
 import android.telephony.ClientRequestStats;
-import android.telephony.Rlog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.telephony.Rlog;
+
 import java.util.ArrayList;
 
 public class ClientWakelockAccountant {
diff --git a/src/java/com/android/internal/telephony/CommandException.java b/src/java/com/android/internal/telephony/CommandException.java
index 31ffcd2..ccd9251 100644
--- a/src/java/com/android/internal/telephony/CommandException.java
+++ b/src/java/com/android/internal/telephony/CommandException.java
@@ -16,8 +16,9 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
+
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index de4f7c0..cf6c38c 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -16,16 +16,18 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.KeepalivePacketData;
 import android.net.LinkProperties;
 import android.os.Handler;
 import android.os.Message;
 import android.os.WorkSource;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.CarrierRestrictionRules;
 import android.telephony.ClientRequestStats;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.data.DataProfile;
 import android.telephony.emergency.EmergencyNumber;
 
@@ -73,6 +75,7 @@
     static final String CB_FACILITY_BA_MT        = "AC";
     static final String CB_FACILITY_BA_SIM       = "SC";
     static final String CB_FACILITY_BA_FD        = "FD";
+    static final String CB_FACILITY_BIC_ACR      = "AR";
 
 
     // Used for various supp services apis
@@ -480,6 +483,20 @@
     void unSetOnSs(Handler h);
 
     /**
+     * Register for unsolicited NATT Keepalive Status Indications
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    default void setOnRegistrationFailed(Handler h, int what, Object obj) {}
+
+    /**
+     * @param h Handler for notification message.
+     */
+    default void unSetOnRegistrationFailed(Handler h) {}
+
+    /**
      * Sets the handler for Event Notifications for CDMA Display Info.
      * Unlike the register* methods, there's only one notification handler
      *
@@ -654,6 +671,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
@@ -1151,6 +1184,8 @@
      */
     void sendCdmaSms(byte[] pdu, Message response);
 
+    void sendCdmaSMSExpectMore(byte[] pdu, Message response);
+
     /**
      * send SMS over IMS with 3GPP/GSM SMS format
      * @param smscPDU is smsc address in PDU form GSM BCD format prefixed
@@ -1342,8 +1377,15 @@
     @UnsupportedAppUsage
     void setNetworkSelectionModeAutomatic(Message response);
 
+    /**
+     * Ask the radio to connect to the input network with specific RadioAccessNetwork
+     * and change selection mode to manual.
+     * @param operatorNumeric PLMN ID of the network to select.
+     * @param ran radio access network type (see {@link AccessNetworkType}).
+     * @param response callback message.
+     */
     @UnsupportedAppUsage
-    void setNetworkSelectionModeManual(String operatorNumeric, Message response);
+    void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message response);
 
     /**
      * Queries whether the current network selection mode is automatic
@@ -2229,17 +2271,30 @@
     void setUnsolResponseFilter(int filter, Message result);
 
     /**
-     * Send the signal strength reporting criteria to the modem.
+     * Sets the signal strength reporting criteria.
      *
-     * @param hysteresisMs A hysteresis time in milliseconds. A value of 0 disables hysteresis.
-     * @param hysteresisDb An interval in dB defining the required magnitude change between reports.
-     *     A value of 0 disables hysteresis.
-     * @param thresholdsDbm An array of trigger thresholds in dBm. A size of 0 disables thresholds.
-     * @param ran RadioAccessNetwork for which to apply criteria.
+     * The resulting reporting rules are the AND of all the supplied criteria. For each RAN
+     * The hysteresisDb and thresholds apply to only the following measured quantities:
+     * -GERAN    - RSSI
+     * -CDMA2000 - RSSI
+     * -UTRAN    - RSCP
+     * -EUTRAN   - RSRP/RSRQ/RSSNR
+     * -NGRAN    - SSRSRP/SSRSRQ/SSSINR
+     *
+     * Note: Reporting criteria must be individually set for each RAN. For any unset reporting
+     * criteria, the value is implementation-defined.
+     *
+     * Response callback is
+     * IRadioResponse.setSignalStrengthReportingCriteriaResponse_1_5()
+     *
+     * @param signalThresholdInfo Signal threshold info including the threshold values,
+     *                            hysteresisDb, and hysteresisMs. See @1.5::SignalThresholdInfo
+     *                            for details.
+     * @param ran The type of network for which to apply these thresholds.
      * @param result callback message contains the information of SUCCESS/FAILURE
      */
-    void setSignalStrengthReportingCriteria(int hysteresisMs, int hysteresisDb, int[] thresholdsDbm,
-            int ran, Message result);
+    void setSignalStrengthReportingCriteria(SignalThresholdInfo signalThresholdInfo, int ran,
+            Message result);
 
     /**
      * Send the link capacity reporting criteria to the modem
@@ -2378,6 +2433,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/Connection.java b/src/java/com/android/internal/telephony/Connection.java
old mode 100755
new mode 100644
index ede22e1..18901ce
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -16,19 +16,21 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.telephony.DisconnectCause;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.ServiceState.RilRadioTechnology;
 import android.telephony.emergency.EmergencyNumber;
 import android.util.Log;
 
 import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -41,6 +43,8 @@
 public abstract class Connection {
     private static final String TAG = "Connection";
 
+    public static final String ADHOC_CONFERENCE_ADDRESS = "tel:conf-factory";
+
     public interface PostDialListener {
         void onPostDialWait();
         void onPostDialChar(char c);
@@ -94,7 +98,7 @@
     public interface Listener {
         public void onVideoStateChanged(int videoState);
         public void onConnectionCapabilitiesChanged(int capability);
-        public void onCallRadioTechChanged(@ServiceState.RilRadioTechnology int vrat);
+        public void onCallRadioTechChanged(@RilRadioTechnology int vrat);
         public void onVideoProviderChanged(
                 android.telecom.Connection.VideoProvider videoProvider);
         public void onAudioQualityChanged(int audioQuality);
@@ -125,7 +129,7 @@
         @Override
         public void onConnectionCapabilitiesChanged(int capability) {}
         @Override
-        public void onCallRadioTechChanged(@ServiceState.RilRadioTechnology int vrat) {}
+        public void onCallRadioTechChanged(@RilRadioTechnology int vrat) {}
         @Override
         public void onVideoProviderChanged(
                 android.telecom.Connection.VideoProvider videoProvider) {}
@@ -183,6 +187,8 @@
     protected String mAddress;     // MAY BE NULL!!!
     @UnsupportedAppUsage
     protected String mDialString;          // outgoing calls only
+    protected String[] mParticipantsToDial;// outgoing calls only
+    protected boolean mIsAdhocConference;
     @UnsupportedAppUsage
     protected int mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED;
     @UnsupportedAppUsage
@@ -216,6 +222,9 @@
     protected int mCause = DisconnectCause.NOT_DISCONNECTED;
     protected PostDialState mPostDialState = PostDialState.NOT_STARTED;
 
+    // Store the current audio code
+    protected int mAudioCodec;
+
     @UnsupportedAppUsage
     private static String LOG_TAG = "Connection";
 
@@ -227,7 +236,7 @@
      *
      * This is used to propagate the call radio technology to upper layer.
      */
-    private @ServiceState.RilRadioTechnology int mCallRadioTech =
+    private @RilRadioTechnology int mCallRadioTech =
             ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
     private boolean mAudioModeIsVoip;
     private int mAudioQuality;
@@ -238,6 +247,7 @@
     private int mPhoneType;
     private boolean mAnsweringDisconnectsActiveCall;
     private boolean mAllowAddCallDuringVideoCall;
+    private boolean mAllowHoldingVideoCall;
 
     private boolean mIsEmergencyCall;
 
@@ -308,6 +318,20 @@
     }
 
     /**
+     * Gets the participants address (e.g. phone number) associated with connection.
+     *
+     * @return address or null if unavailable
+     */
+    public String[] getParticipantsToDial() {
+        return mParticipantsToDial;
+    }
+
+    // return whether connection is AdhocConference or not
+    public boolean isAdhocConference() {
+        return mIsAdhocConference;
+    }
+
+    /**
      * Gets CNAP name associated with connection.
      * @return cnap name or null if unavailable
      */
@@ -902,7 +926,7 @@
      * @return the RIL Voice Radio Technology used for current connection,
      *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
      */
-    public @ServiceState.RilRadioTechnology int getCallRadioTech() {
+    public @RilRadioTechnology int getCallRadioTech() {
         return mCallRadioTech;
     }
 
@@ -980,7 +1004,7 @@
      * @param vrat the RIL voice radio technology for current connection,
      *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
      */
-    public void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+    public void setCallRadioTech(@RilRadioTechnology int vrat) {
         if (mCallRadioTech == vrat) {
             return;
         }
@@ -1024,7 +1048,7 @@
             int previousCount = mExtras.size();
             // Prevent vendors from passing in extras other than primitive types and android API
             // parcelables.
-            mExtras = mExtras.filterValues();
+            mExtras = TelephonyUtils.filterValues(mExtras);
             int filteredCount = mExtras.size();
             if (filteredCount != previousCount) {
                 Rlog.i(TAG, "setConnectionExtras: filtering " + (previousCount - filteredCount)
@@ -1075,6 +1099,14 @@
         mAllowAddCallDuringVideoCall = allowAddCallDuringVideoCall;
     }
 
+    public boolean shouldAllowHoldingVideoCall() {
+        return mAllowHoldingVideoCall;
+    }
+
+    public void setAllowHoldingVideoCall(boolean allowHoldingVideoCall) {
+        mAllowHoldingVideoCall = allowHoldingVideoCall;
+    }
+
     /**
      * Sets whether the connection is the result of an external call which was pulled to the local
      * device.
@@ -1354,4 +1386,12 @@
                 .append(" post dial state: " + getPostDialState());
         return str.toString();
     }
+
+    /**
+     * Get current audio codec.
+     * @return current audio codec.
+     */
+    public int getAudioCodec() {
+        return mAudioCodec;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/DebugService.java b/src/java/com/android/internal/telephony/DebugService.java
index 0002f14..3a08243 100644
--- a/src/java/com/android/internal/telephony/DebugService.java
+++ b/src/java/com/android/internal/telephony/DebugService.java
@@ -16,10 +16,10 @@
 
 package com.android.internal.telephony;
 
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 9cce7bc..e8aafe7 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -17,32 +17,28 @@
 package com.android.internal.telephony;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
-import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.telephony.TelephonyRegistryManager;
 import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.CallQuality;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
-import android.telephony.CellLocation;
 import android.telephony.PhoneCapability;
-import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
-import android.telephony.Rlog;
+import android.telephony.PreciseDataConnectionState;
 import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.telephony.data.ApnSetting;
+import android.telephony.TelephonyRegistryManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 
 import com.android.internal.telephony.PhoneInternalInterface.DataActivityState;
+import com.android.telephony.Rlog;
+
 import java.util.List;
 
 /**
@@ -84,7 +80,7 @@
         int phoneId = sender.getPhoneId();
         int subId = sender.getSubId();
 
-        Rlog.d(LOG_TAG, "nofityServiceState: mRegistry=" + mRegistry + " ss=" + ss
+        Rlog.d(LOG_TAG, "notifyServiceState: mRegistry=" + mRegistry + " ss=" + ss
             + " sender=" + sender + " phondId=" + phoneId + " subId=" + subId);
         if (ss == null) {
             ss = new ServiceState();
@@ -134,59 +130,20 @@
     }
 
     @Override
-    public void notifyDataConnection(Phone sender, String apnType,
-        PhoneConstants.DataState state) {
-        doNotifyDataConnection(sender, apnType, state);
-    }
+    public void notifyDataConnection(
+            Phone sender, String apnType, PreciseDataConnectionState preciseState) {
 
-    private void doNotifyDataConnection(Phone sender, String apnType,
-        PhoneConstants.DataState state) {
         int subId = sender.getSubId();
         int phoneId = sender.getPhoneId();
-        long dds = SubscriptionManager.getDefaultDataSubscriptionId();
-        if (DBG) {
-            log("subId = " + subId + ", DDS = " + dds);
-        }
 
-        // TODO
-        // use apnType as the key to which connection we're talking about.
-        // pass apnType back up to fetch particular for this one.
-        TelephonyManager telephony = TelephonyManager.getDefault();
-        LinkProperties linkProperties = null;
-        NetworkCapabilities networkCapabilities = null;
-        boolean roaming = false;
-
-        if (state == PhoneConstants.DataState.CONNECTED) {
-            linkProperties = sender.getLinkProperties(apnType);
-            networkCapabilities = sender.getNetworkCapabilities(apnType);
-        }
-        ServiceState ss = sender.getServiceState();
-        if (ss != null) {
-            roaming = ss.getDataRoaming();
-        }
-        mTelephonyRegistryMgr.notifyDataConnectionForSubscriber(phoneId, subId,
-            PhoneConstantConversions.convertDataState(state),
-            sender.isDataAllowed(ApnSetting.getApnTypesBitmaskFromString(apnType)),
-            sender.getActiveApnHost(apnType),
-            apnType,
-            linkProperties,
-            networkCapabilities,
-            ((telephony != null) ? telephony.getDataNetworkType(subId) :
-                TelephonyManager.NETWORK_TYPE_UNKNOWN), roaming);
+        mTelephonyRegistryMgr.notifyDataConnectionForSubscriber(
+                phoneId, subId, apnType, preciseState);
     }
 
     @Override
-    public void notifyDataConnectionFailed(Phone sender, String apnType) {
-        mTelephonyRegistryMgr.notifyDataConnectionFailed(sender.getSubId(), sender.getPhoneId(),
-            apnType);
-    }
-
-    @Override
-    public void notifyCellLocation(Phone sender, CellLocation cl) {
+    public void notifyCellLocation(Phone sender, CellIdentity cellIdentity) {
         int subId = sender.getSubId();
-        Bundle data = new Bundle();
-        cl.fillInNotifierBundle(data);
-        mTelephonyRegistryMgr.notifyCellLocation(subId, data);
+        mTelephonyRegistryMgr.notifyCellLocation(subId, cellIdentity);
     }
 
     @Override
@@ -195,26 +152,6 @@
         mTelephonyRegistryMgr.notifyCellInfoChanged(subId, cellInfo);
     }
 
-    @Override
-    public void notifyPhysicalChannelConfiguration(Phone sender,
-        List<PhysicalChannelConfig> configs) {
-        int subId = sender.getSubId();
-        int phoneId = sender.getPhoneId();
-        try {
-            if (mRegistry != null) {
-                mRegistry.notifyPhysicalChannelConfigurationForSubscriber(phoneId, subId, configs);
-            }
-        } catch (RemoteException ex) {
-            // system process is dead
-        }
-    }
-
-    @Override
-    public void notifyOtaspChanged(Phone sender, int otaspMode) {
-        int subId = sender.getSubId();
-        mTelephonyRegistryMgr.notifyOtaspChanged(subId, otaspMode);
-    }
-
     public void notifyPreciseCallState(Phone sender) {
         Call ringingCall = sender.getRingingCall();
         Call foregroundCall = sender.getForegroundCall();
@@ -237,7 +174,9 @@
         mTelephonyRegistryMgr.notifyImsDisconnectCause(sender.getSubId(), imsReasonInfo);
     }
 
-    public void notifyPreciseDataConnectionFailed(Phone sender, String apnType,
+    @Override
+    /** Notify the TelephonyRegistry that a data connection has failed with a specified cause */
+    public void notifyDataConnectionFailed(Phone sender, String apnType,
         String apn, @DataFailureCause int failCause) {
         mTelephonyRegistryMgr.notifyPreciseDataConnectionFailed(sender.getSubId(),
             sender.getPhoneId(), apnType, apn, failCause);
@@ -319,6 +258,13 @@
             callQuality, callNetworkType);
     }
 
+    @Override
+    public void notifyRegistrationFailed(Phone sender, @NonNull CellIdentity cellIdentity,
+            @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) {
+        mTelephonyRegistryMgr.notifyRegistrationFailed(sender.getPhoneId(), sender.getSubId(),
+                cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode);
+    }
+
     /**
      * Convert the {@link DataActivityState} enum into the TelephonyManager.DATA_* constants for the
      * public API.
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index f4d782c..c94c4c3 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -36,7 +36,7 @@
 import android.os.PowerManager;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.TelephonyManager;
 import android.util.LocalLog;
 import android.util.SparseIntArray;
@@ -44,6 +44,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -75,6 +76,7 @@
     static final int EVENT_RADIO_AVAILABLE              = 6;
     @VisibleForTesting
     static final int EVENT_WIFI_CONNECTION_CHANGED      = 7;
+    static final int EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH = 8;
 
     // TODO(b/74006656) load hysteresis values from a property when DeviceStateMonitor starts
     private static final int HYSTERESIS_KBPS = 50;
@@ -162,6 +164,11 @@
      */
     private boolean mIsWifiConnected;
 
+    /**
+     * True indicates we should always enable the signal strength reporting from radio.
+     */
+    private boolean mIsAlwaysSignalStrengthReportingEnabled;
+
     @VisibleForTesting
     static final int CELL_INFO_INTERVAL_SHORT_MS = 2000;
     @VisibleForTesting
@@ -312,7 +319,8 @@
         // 3. When the update mode is IGNORE_SCREEN_OFF. This mode is used in some corner cases like
         //    when Bluetooth carkit is connected, we still want to update signal strength even
         //    when screen is off.
-        if (mIsCharging || mIsScreenOn
+        // 4. Any of system services is registrating to always listen to signal strength changes
+        if (mIsAlwaysSignalStrengthReportingEnabled || mIsCharging || mIsScreenOn
                 || mUpdateModes.get(TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH)
                 == TelephonyManager.INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF) {
             return false;
@@ -409,6 +417,15 @@
         sendMessage(obtainMessage(EVENT_UPDATE_MODE_CHANGED, filters, mode));
     }
 
+    /**
+     * Set if Telephony need always report signal strength.
+     *
+     * @param isEnable
+     */
+    public void setAlwaysReportSignalStrength(boolean isEnable) {
+        sendMessage(obtainMessage(EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH, isEnable ? 1 : 0));
+    }
+
     private void onSetIndicationUpdateMode(int filters, int mode) {
         if ((filters & TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH) != 0) {
             mUpdateModes.put(TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, mode);
@@ -452,6 +469,9 @@
             case EVENT_WIFI_CONNECTION_CHANGED:
                 onUpdateDeviceState(msg.what, msg.arg1 != WIFI_UNAVAILABLE);
                 break;
+            case EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH:
+                onUpdateDeviceState(msg.what, msg.arg1 != 0);
+                break;
             default:
                 throw new IllegalStateException("Unexpected message arrives. msg = " + msg.what);
         }
@@ -486,7 +506,10 @@
             case EVENT_WIFI_CONNECTION_CHANGED:
                 if (mIsWifiConnected == state) return;
                 mIsWifiConnected = state;
-
+                break;
+            case EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH:
+                if (mIsAlwaysSignalStrengthReportingEnabled == state) return;
+                mIsAlwaysSignalStrengthReportingEnabled = state;
                 break;
             default:
                 return;
@@ -587,14 +610,28 @@
     }
 
     private void setSignalStrengthReportingCriteria() {
-        mPhone.setSignalStrengthReportingCriteria(
-                AccessNetworkThresholds.GERAN, AccessNetworkType.GERAN);
-        mPhone.setSignalStrengthReportingCriteria(
-                AccessNetworkThresholds.UTRAN, AccessNetworkType.UTRAN);
-        mPhone.setSignalStrengthReportingCriteria(
-                AccessNetworkThresholds.EUTRAN, AccessNetworkType.EUTRAN);
-        mPhone.setSignalStrengthReportingCriteria(
-                AccessNetworkThresholds.CDMA2000, AccessNetworkType.CDMA2000);
+        mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSSI,
+                AccessNetworkThresholds.GERAN, AccessNetworkType.GERAN, true);
+        mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSCP,
+                AccessNetworkThresholds.UTRAN, AccessNetworkType.UTRAN, true);
+        mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSRP,
+                AccessNetworkThresholds.EUTRAN_RSRP, AccessNetworkType.EUTRAN, true);
+        mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSSI,
+                AccessNetworkThresholds.CDMA2000, AccessNetworkType.CDMA2000, true);
+        if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSRQ,
+                    AccessNetworkThresholds.EUTRAN_RSRQ, AccessNetworkType.EUTRAN, false);
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSSNR,
+                    AccessNetworkThresholds.EUTRAN_RSSNR, AccessNetworkType.EUTRAN, true);
+
+            // Defaultly we only need SSRSRP for NGRAN signal criterial reporting
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_SSRSRP,
+                    AccessNetworkThresholds.NGRAN_RSRSRP, AccessNetworkType.NGRAN, true);
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_SSRSRQ,
+                    AccessNetworkThresholds.NGRAN_RSRSRQ, AccessNetworkType.NGRAN, false);
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_SSSINR,
+                    AccessNetworkThresholds.NGRAN_SSSINR, AccessNetworkType.NGRAN, false);
+        }
     }
 
     private void setLinkCapacityReportingCriteria() {
@@ -730,11 +767,11 @@
         };
 
         /**
-         * List of default dBm thresholds for EUTRAN {@link AccessNetworkType}.
+         * List of default dBm RSRP thresholds for EUTRAN {@link AccessNetworkType}.
          *
          * These thresholds are taken from the LTE RSRP defaults in {@link CarrierConfigManager}.
          */
-        public static final int[] EUTRAN = new int[] {
+        public static final int[] EUTRAN_RSRP = new int[] {
             -128, /* SIGNAL_STRENGTH_POOR */
             -118, /* SIGNAL_STRENGTH_MODERATE */
             -108, /* SIGNAL_STRENGTH_GOOD */
@@ -742,6 +779,30 @@
         };
 
         /**
+         * List of default dB RSRQ thresholds for EUTRAN {@link AccessNetworkType}.
+         *
+         * These thresholds are taken from the LTE RSRQ defaults in {@link CarrierConfigManager}.
+         */
+        public static final int[] EUTRAN_RSRQ = new int[] {
+            -19,  /* SIGNAL_STRENGTH_POOR */
+            -17,  /* SIGNAL_STRENGTH_MODERATE */
+            -14,  /* SIGNAL_STRENGTH_GOOD */
+            -12   /* SIGNAL_STRENGTH_GREAT */
+        };
+
+        /**
+         * List of default 10*dB RSSNR thresholds for EUTRAN {@link AccessNetworkType}.
+         *
+         * These thresholds are taken from the LTE RSSNR defaults in {@link CarrierConfigManager}.
+         */
+        public static final int[] EUTRAN_RSSNR = new int[] {
+            -30,  /* SIGNAL_STRENGTH_POOR */
+            10,   /* SIGNAL_STRENGTH_MODERATE */
+            45,   /* SIGNAL_STRENGTH_GOOD */
+            130   /* SIGNAL_STRENGTH_GREAT */
+        };
+
+        /**
          * List of dBm thresholds for CDMA2000 {@link AccessNetworkType}.
          *
          * These correspond to EVDO level thresholds.
@@ -752,6 +813,36 @@
             -75,
             -65
         };
+
+        /**
+         * List of dB thresholds for NGRAN {@link AccessNetworkType} RSRSRP
+         */
+        public static final int[] NGRAN_RSRSRP = new int[] {
+            -110, /* SIGNAL_STRENGTH_POOR */
+            -90, /* SIGNAL_STRENGTH_MODERATE */
+            -80, /* SIGNAL_STRENGTH_GOOD */
+            -65,  /* SIGNAL_STRENGTH_GREAT */
+        };
+
+        /**
+         * List of dB thresholds for NGRAN {@link AccessNetworkType} RSRSRP
+         */
+        public static final int[] NGRAN_RSRSRQ = new int[] {
+            -16, /* SIGNAL_STRENGTH_POOR */
+            -11, /* SIGNAL_STRENGTH_MODERATE */
+            -9, /* SIGNAL_STRENGTH_GOOD */
+            -7  /* SIGNAL_STRENGTH_GREAT */
+        };
+
+        /**
+         * List of dB thresholds for NGRAN {@link AccessNetworkType} SSSINR
+         */
+        public static final int[] NGRAN_SSSINR = new int[] {
+            -5, /* SIGNAL_STRENGTH_POOR */
+            5, /* SIGNAL_STRENGTH_MODERATE */
+            15, /* SIGNAL_STRENGTH_GOOD */
+            30  /* SIGNAL_STRENGTH_GREAT */
+        };
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/DriverCall.java b/src/java/com/android/internal/telephony/DriverCall.java
index 3a7947d..a67de7a 100644
--- a/src/java/com/android/internal/telephony/DriverCall.java
+++ b/src/java/com/android/internal/telephony/DriverCall.java
@@ -16,9 +16,10 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaCall.java b/src/java/com/android/internal/telephony/GsmCdmaCall.java
index da2b057..cc1b2c0 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaCall.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaCall.java
@@ -16,7 +16,8 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.List;
 
 /**
@@ -60,6 +61,16 @@
         mOwner.hangup(this);
     }
 
+    /**
+     * Hangup the ringing call with a specified reason; reason is not supported on GSM/CDMA.
+     * @param rejectReason
+     */
+    @Override
+    public void hangup(@android.telecom.Call.RejectReason int rejectReason)
+            throws CallStateException {
+        mOwner.hangup(this);
+    }
+
     @Override
     public String toString() {
         return mState.toString();
diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
index 1bbcd5e..2e86855 100755
--- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -28,14 +28,13 @@
 import android.os.PersistableBundle;
 import android.os.Registrant;
 import android.os.RegistrantList;
-import android.os.SystemProperties;
+import android.sysprop.TelephonyProperties;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
+import android.telephony.ServiceState.RilRadioTechnology;
 import android.telephony.TelephonyManager;
 import android.telephony.cdma.CdmaCellLocation;
 import android.telephony.gsm.GsmCellLocation;
@@ -45,6 +44,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -656,14 +656,13 @@
      * @throws CallStateException
      */
     public void checkForDialIssues(boolean isEmergencyCall) throws CallStateException {
-        String disableCall = SystemProperties.get(
-                TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
+        boolean disableCall = TelephonyProperties.disable_call().orElse(false);
 
         if (mCi.getRadioState() != TelephonyManager.RADIO_POWER_ON) {
             throw new CallStateException(CallStateException.ERROR_POWER_OFF,
                     "Modem not powered");
         }
-        if (disableCall.equals("true")) {
+        if (disableCall) {
             throw new CallStateException(CallStateException.ERROR_CALLING_DISABLED,
                     "Calling disabled via ro.telephony.disable-call property");
         }
@@ -896,8 +895,6 @@
                                 hoConnection.mPreHandoverState != GsmCdmaCall.State.HOLDING &&
                                 dc.state == DriverCall.State.ACTIVE) {
                             mConnections[i].onConnectedInOrOut();
-                        } else {
-                            mConnections[i].onConnectedConnectionMigrated();
                         }
 
                         mHandoverConnections.remove(hoConnection);
@@ -1468,6 +1465,13 @@
                 if (isPhoneTypeGsm()) {
                     ar = (AsyncResult) msg.obj;
                     if (ar.exception != null) {
+                        if (msg.what == EVENT_SWITCH_RESULT) {
+                            Connection connection = mForegroundCall.getLatestConnection();
+                            if (connection != null) {
+                                connection.onConnectionEvent(
+                                        android.telecom.Connection.EVENT_CALL_SWITCH_FAILED, null);
+                            }
+                        }
                         mPhone.notifySuppServiceFailed(getFailedService(msg.what));
                     }
                     operationComplete();
@@ -1534,7 +1538,7 @@
                     causeCode == CallFailCause.BEARER_NOT_AVAIL ||
                     causeCode == CallFailCause.ERROR_UNSPECIFIED) {
 
-                    CellLocation loc = mPhone.getCellLocation();
+                    CellLocation loc = mPhone.getCellIdentity().asCellLocation();
                     int cid = -1;
                     if (loc != null) {
                         if (loc instanceof GsmCellLocation) {
@@ -1654,7 +1658,7 @@
      * @param vrat the RIL voice radio technology for CS calls,
      *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
      */
-    public void dispatchCsCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+    public void dispatchCsCallRadioTech(@RilRadioTechnology int vrat) {
         if (mConnections == null) {
             log("dispatchCsCallRadioTech: mConnections is null");
             return;
diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
index b3dea8e..1c49f20 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
@@ -15,28 +15,28 @@
  */
 
 package com.android.internal.telephony;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
-import android.os.PowerManager;
 import android.os.Registrant;
 import android.os.SystemClock;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
 import com.android.internal.telephony.uicc.UiccCardApplication;
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
@@ -74,27 +74,20 @@
 
     Handler mHandler;
 
-    private PowerManager.WakeLock mPartialWakeLock;
-
     // The cached delay to be used between DTMF tones fetched from carrier config.
     private int mDtmfToneDelay = 0;
 
-    // Store the current audio codec
-    private int mAudioCodec = DriverCall.AUDIO_QUALITY_UNSPECIFIED;
-
     private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
 
     //***** Event Constants
     static final int EVENT_DTMF_DONE = 1;
     static final int EVENT_PAUSE_DONE = 2;
     static final int EVENT_NEXT_POST_DIAL = 3;
-    static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
     static final int EVENT_DTMF_DELAY_DONE = 5;
 
     //***** Constants
     static final int PAUSE_DELAY_MILLIS_GSM = 3 * 1000;
     static final int PAUSE_DELAY_MILLIS_CDMA = 2 * 1000;
-    static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000;
 
     //***** Inner Classes
 
@@ -111,9 +104,6 @@
                 case EVENT_PAUSE_DONE:
                     processNextPostDialChar();
                     break;
-                case EVENT_WAKE_LOCK_TIMEOUT:
-                    releaseWakeLock();
-                    break;
                 case EVENT_DTMF_DONE:
                     // We may need to add a delay specified by carrier between DTMF tones that are
                     // sent out.
@@ -129,8 +119,6 @@
     /** This is probably an MT call that we first saw in a CLCC response or a hand over. */
     public GsmCdmaConnection (GsmCdmaPhone phone, DriverCall dc, GsmCdmaCallTracker ct, int index) {
         super(phone.getPhoneType());
-        createWakeLock(phone.getContext());
-        acquireWakeLock();
 
         mOwner = ct;
         mHandler = new MyHandler(mOwner.getLooper());
@@ -161,8 +149,6 @@
     public GsmCdmaConnection (GsmCdmaPhone phone, String dialString, GsmCdmaCallTracker ct,
                               GsmCdmaCall parent, boolean isEmergencyCall) {
         super(phone.getPhoneType());
-        createWakeLock(phone.getContext());
-        acquireWakeLock();
 
         mOwner = ct;
         mHandler = new MyHandler(mOwner.getLooper());
@@ -217,8 +203,6 @@
     public GsmCdmaConnection(Context context, CdmaCallWaitingNotification cw, GsmCdmaCallTracker ct,
                              GsmCdmaCall parent) {
         super(parent.getPhone().getPhoneType());
-        createWakeLock(context);
-        acquireWakeLock();
 
         mOwner = ct;
         mHandler = new MyHandler(mOwner.getLooper());
@@ -242,7 +226,6 @@
         if (mParent != null) {
             mParent.detach(this);
         }
-        releaseAllWakeLocks();
     }
 
     static boolean equalsHandlesNulls(Object a, Object b) {
@@ -623,7 +606,6 @@
             mOrigConnection = null;
         }
         clearPostDialListeners();
-        releaseWakeLock();
         return changed;
     }
 
@@ -639,7 +621,6 @@
                 mParent.detach(this);
             }
         }
-        releaseWakeLock();
     }
 
     // Returns true if state has changed, false if nothing changed
@@ -780,23 +761,9 @@
         if (!mIsIncoming) {
             // outgoing calls only
             processNextPostDialChar();
-        } else {
-            // Only release wake lock for incoming calls, for outgoing calls the wake lock
-            // will be released after any pause-dial is completed
-            releaseWakeLock();
         }
     }
 
-    /**
-     * We have completed the migration of another connection to this GsmCdmaConnection (for example,
-     * in the case of SRVCC) and not still DIALING/ALERTING/INCOMING/WAITING.
-     */
-    void onConnectedConnectionMigrated() {
-        // We can release the wakelock in this case, the migrated call is not still
-        // DIALING/ALERTING/INCOMING/WAITING.
-        releaseWakeLock();
-    }
-
     private void
     doDisconnect() {
         mIndex = -1;
@@ -881,17 +848,7 @@
     @Override
     protected void finalize()
     {
-        /**
-         * It is understood that This finalizer is not guaranteed
-         * to be called and the release lock call is here just in
-         * case there is some path that doesn't call onDisconnect
-         * and or onConnectedInOrOut.
-         */
-        if (mPartialWakeLock != null && mPartialWakeLock.isHeld()) {
-            Rlog.e(LOG_TAG, "UNEXPECTED; mPartialWakeLock is held when finalizing.");
-        }
         clearPostDialListeners();
-        releaseWakeLock();
     }
 
     private void
@@ -900,7 +857,6 @@
         Registrant postDialHandler;
 
         if (mPostDialState == PostDialState.CANCELLED) {
-            releaseWakeLock();
             return;
         }
 
@@ -908,9 +864,6 @@
                 mPostDialString.length() <= mNextPostDialChar) {
             setPostDialState(PostDialState.COMPLETE);
 
-            // We were holding a wake lock until pause-dial was complete, so give it up now
-            releaseWakeLock();
-
             // notifyMessage.arg1 is 0 on complete
             c = 0;
         } else {
@@ -1004,60 +957,18 @@
      * @param s new PostDialState
      */
     private void setPostDialState(PostDialState s) {
-        if (s == PostDialState.STARTED ||
-                s == PostDialState.PAUSE) {
-            synchronized (mPartialWakeLock) {
-                if (mPartialWakeLock.isHeld()) {
-                    mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
-                } else {
-                    acquireWakeLock();
-                }
-                Message msg = mHandler.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
-                mHandler.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
-            }
-        } else {
-            mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
-            releaseWakeLock();
-        }
         mPostDialState = s;
         notifyPostDialListeners();
     }
 
     @UnsupportedAppUsage
     private void createWakeLock(Context context) {
-        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
+        // no-op
     }
 
     @UnsupportedAppUsage
     private void acquireWakeLock() {
-        if (mPartialWakeLock != null) {
-            synchronized (mPartialWakeLock) {
-                log("acquireWakeLock");
-                mPartialWakeLock.acquire();
-            }
-        }
-    }
-
-    private void releaseWakeLock() {
-        if (mPartialWakeLock != null) {
-            synchronized (mPartialWakeLock) {
-                if (mPartialWakeLock.isHeld()) {
-                    log("releaseWakeLock");
-                    mPartialWakeLock.release();
-                }
-            }
-        }
-    }
-
-    private void releaseAllWakeLocks() {
-        if (mPartialWakeLock != null) {
-            synchronized (mPartialWakeLock) {
-                while (mPartialWakeLock.isHeld()) {
-                    mPartialWakeLock.release();
-                }
-            }
-        }
+        // no-op
     }
 
     @UnsupportedAppUsage
@@ -1205,6 +1116,20 @@
     }
 
     /**
+     * Get the corresponding EmergencyNumberTracker associated with the connection.
+     * @return the EmergencyNumberTracker
+     */
+    public EmergencyNumberTracker getEmergencyNumberTracker() {
+        if (mOwner != null) {
+            Phone phone = mOwner.getPhone();
+            if (phone != null) {
+                return phone.getEmergencyNumberTracker();
+            }
+        }
+        return null;
+    }
+
+    /**
      * @return {@code true} if this call is an OTASP activation call, {@code false} otherwise.
      */
     public boolean isOtaspCall() {
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 82bb78b..e703b2a 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -30,8 +30,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -55,16 +55,20 @@
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Telephony;
+import android.sysprop.TelephonyProperties;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CarrierConfigManager;
-import android.telephony.CellLocation;
+import android.telephony.CellIdentity;
+import android.telephony.DataFailCause;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkScanRequest;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import android.telephony.PreciseDataConnectionState;
 import android.telephony.ServiceState;
+import android.telephony.ServiceState.RilRadioTechnology;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -86,6 +90,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;
@@ -98,7 +103,8 @@
 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 com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -135,7 +141,7 @@
 
     //CDMA
     // Default Emergency Callback Mode exit timer
-    private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
+    private static final long DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
     public static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
     public static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
@@ -150,6 +156,7 @@
     private String mMeid;
     // string to define how the carrier specifies its own ota sp number
     private String mCarrierOtaSpNumSchema;
+    private Boolean mUiccApplicationsEnabled = null;
 
     // A runnable which is used to automatically exit from Ecm after a period of time.
     private Runnable mExitEcmRunnable = new Runnable() {
@@ -322,7 +329,10 @@
         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);
+        mCi.setOnRegistrationFailed(this, EVENT_REGISTRATION_FAILED, null);
 
         //GSM
         mCi.setOnUSSD(this, EVENT_USSD, null);
@@ -340,8 +350,8 @@
         mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone(
                 getPhoneId(), "");
 
-        mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
-                TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
+        mResetModemOnRadioTechnologyChange = TelephonyProperties.reset_on_radio_tech_change()
+                .orElse(false);
 
         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
         mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
@@ -378,8 +388,7 @@
             mIsPhoneInEcmState = getInEcmMode();
             if (mIsPhoneInEcmState) {
                 // Send a message which will invoke handleExitEmergencyCallbackMode
-                mCi.exitEmergencyCallbackMode(
-                        obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
+                mCi.exitEmergencyCallbackMode(null);
             }
 
             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
@@ -495,6 +504,7 @@
 
     @UnsupportedAppUsage
     @Override
+    @NonNull
     public ServiceState getServiceState() {
         if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) {
             if (mImsPhone != null) {
@@ -512,8 +522,8 @@
     }
 
     @Override
-    public void getCellLocation(WorkSource workSource, Message rspMsg) {
-        mSST.requestCellLocation(workSource, rspMsg);
+    public void getCellIdentity(WorkSource workSource, Message rspMsg) {
+        mSST.requestCellIdentity(workSource, rspMsg);
     }
 
     @UnsupportedAppUsage
@@ -586,12 +596,53 @@
         return mPendingMMIs;
     }
 
+    private @NonNull DcTracker getActiveDcTrackerForApn(@NonNull String apnType) {
+        int currentTransport = mTransportManager.getCurrentTransport(
+                ApnSetting.getApnTypesBitmaskFromString(apnType));
+        return getDcTracker(currentTransport);
+    }
+
+    @Override
+    public PreciseDataConnectionState getPreciseDataConnectionState(String apnType) {
+        // If we are OOS, then all data connections are null.
+        // FIXME: we need to figure out how to report the EIMS PDN connectivity here, which
+        // should imply emergency attach - today emergency attach is unknown at the AP,
+        // so, we take a guess.
+        boolean isEmergencyData = isPhoneTypeGsm()
+                && apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY);
+
+        if (mSST == null
+                || ((mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE)
+                        && !isEmergencyData)) {
+            return new PreciseDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
+                    TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                    ApnSetting.getApnTypesBitmaskFromString(apnType),
+                    apnType, null, DataFailCause.NONE, null);
+        }
+
+        // must never be null
+        final DcTracker dctForApn = getActiveDcTrackerForApn(apnType);
+
+        int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        // Always non-null
+        ServiceState ss = getServiceState();
+        if (ss != null) {
+            networkType = ss.getDataNetworkType();
+        }
+
+        return dctForApn.getPreciseDataConnectionState(apnType, isDataSuspended(), networkType);
+    }
+
+    boolean isDataSuspended() {
+        return mCT.mState != PhoneConstants.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed();
+    }
+
     @Override
     public PhoneConstants.DataState getDataConnectionState(String apnType) {
         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
 
         if (mSST == null) {
-            // Radio Technology Change is ongoning, dispose() and removeReferences() have
+            // Radio Technology Change is ongoing, dispose() and removeReferences() have
             // already been called
 
             ret = PhoneConstants.DataState.DISCONNECTED;
@@ -612,8 +663,7 @@
                 switch (getDcTracker(currentTransport).getState(apnType)) {
                     case CONNECTED:
                     case DISCONNECTING:
-                        if (mCT.mState != PhoneConstants.State.IDLE
-                                && !mSST.isConcurrentVoiceAndDataAllowed()) {
+                        if (isDataSuspended()) {
                             ret = PhoneConstants.DataState.SUSPENDED;
                         } else {
                             ret = PhoneConstants.DataState.CONNECTED;
@@ -761,12 +811,12 @@
     }
 
     /**
-     * Notify that the CellLocation has changed.
+     * Notify that the cell location has changed.
      *
-     * @param cl the new CellLocation
+     * @param cellIdentity the new CellIdentity
      */
-    public void notifyLocationChanged(CellLocation cl) {
-        mNotifier.notifyCellLocation(this, cl);
+    public void notifyLocationChanged(CellIdentity cellIdentity) {
+        mNotifier.notifyCellLocation(this, cellIdentity);
     }
 
     @Override
@@ -947,27 +997,27 @@
     /**
      * ImsService reports "IN_SERVICE" for its voice registration state even if the device
      * has lost the physical link to the tower. This helper method merges the IMS and modem
-     * ServiceState, only overriding the voice registration state when we are registered to IMS over
-     * IWLAN. In this case the voice registration state will always be "OUT_OF_SERVICE", so override
-     * the voice registration state with the data registration state.
+     * ServiceState, only overriding the voice registration state when we are registered to IMS. In
+     * this case the voice registration state may be "OUT_OF_SERVICE", so override the voice
+     * registration state with the data registration state.
      */
     private ServiceState mergeServiceStates(ServiceState baseSs, ServiceState imsSs) {
+        // No need to merge states if the baseSs is IN_SERVICE.
+        if (baseSs.getState() == ServiceState.STATE_IN_SERVICE) {
+            return baseSs;
+        }
         // "IN_SERVICE" in this case means IMS is registered.
-        if (imsSs.getVoiceRegState() != ServiceState.STATE_IN_SERVICE) {
+        if (imsSs.getState() != ServiceState.STATE_IN_SERVICE) {
             return baseSs;
         }
 
-        if (imsSs.getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
-            ServiceState newSs = new ServiceState(baseSs);
-            // Voice override for IWLAN. In this case, voice registration is OUT_OF_SERVICE, but
-            // the data RAT is IWLAN, so use that as a basis for determining whether or not the
-            // physical link is available.
-            newSs.setVoiceRegState(baseSs.getDataRegState());
-            newSs.setEmergencyOnly(false); // only get here if voice is IN_SERVICE
-            return newSs;
-        }
-
-        return baseSs;
+        ServiceState newSs = new ServiceState(baseSs);
+        // Voice override for IMS case. In this case, voice registration is OUT_OF_SERVICE, but
+        // IMS is available, so use data registration state as a basis for determining
+        // whether or not the physical link is available.
+        newSs.setVoiceRegState(baseSs.getDataRegistrationState());
+        newSs.setEmergencyOnly(false); // only get here if voice is IN_SERVICE
+        return newSs;
     }
 
     private boolean handleCallDeflectionIncallSupplementaryService(
@@ -1171,6 +1221,38 @@
                 ringingCallState.isAlive());
     }
 
+    private boolean useImsForCall(DialArgs dialArgs) {
+        return isImsUseEnabled()
+                && mImsPhone != null
+                && (mImsPhone.isVolteEnabled() || mImsPhone.isWifiCallingEnabled() ||
+                (mImsPhone.isVideoEnabled() && VideoProfile.isVideo(dialArgs.videoState)))
+                && (mImsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
+    }
+
+    @Override
+    public Connection startConference(String[] participantsToDial, DialArgs dialArgs)
+            throws CallStateException {
+        Phone imsPhone = mImsPhone;
+        boolean useImsForCall = useImsForCall(dialArgs);
+        logd("useImsForCall=" + useImsForCall);
+        if (useImsForCall) {
+            try {
+                if (DBG) logd("Trying IMS PS Conference call");
+                return imsPhone.startConference(participantsToDial, dialArgs);
+            } catch (CallStateException e) {
+                if (DBG) logd("IMS PS conference call exception " + e +
+                        "useImsForCall =" + useImsForCall + ", imsPhone =" + imsPhone);
+                 CallStateException ce = new CallStateException(e.getError(), e.getMessage());
+                 ce.setStackTrace(e.getStackTrace());
+                 throw ce;
+            }
+        } else {
+            throw new CallStateException(
+                CallStateException.ERROR_OUT_OF_SERVICE,
+                "cannot dial conference call in out of service");
+        }
+    }
+
     @Override
     public Connection dial(String dialString, @NonNull DialArgs dialArgs)
             throws CallStateException {
@@ -1191,11 +1273,7 @@
         boolean allowWpsOverIms = configManager.getConfigForSubId(getSubId())
                 .getBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL);
 
-        boolean useImsForCall = isImsUseEnabled()
-                 && imsPhone != null
-                 && (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||
-                 (imsPhone.isVideoEnabled() && VideoProfile.isVideo(dialArgs.videoState)))
-                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
+        boolean useImsForCall = useImsForCall(dialArgs)
                  && (isWpsCall ? allowWpsOverIms : true);
 
         boolean useImsForEmergency = imsPhone != null
@@ -1252,7 +1330,8 @@
         }
 
         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
-                && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {
+                && mSST.mSS.getDataRegistrationState() != ServiceState.STATE_IN_SERVICE
+                && !isEmergency) {
             throw new CallStateException("cannot dial in current state");
         }
         // Check non-emergency voice CS call - shouldn't dial when POWER_OFF
@@ -1265,11 +1344,12 @@
                 "cannot dial voice call in airplane mode");
         }
         // Check for service before placing non emergency CS voice call.
-        // Allow dial only if either CS is camped on any RAT (or) PS is in LTE service.
+        // Allow dial only if either CS is camped on any RAT (or) PS is in LTE/NR service.
         if (mSST != null
                 && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE /* CS out of service */
-                && !(mSST.mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
-                    && ServiceState.isLte(mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE */
+                && !(mSST.mSS.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE
+                && ServiceState.isPsOnlyTech(
+                        mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE/NR */
                 && !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
                 && !isEmergency /* non-emergency call */) {
             throw new CallStateException(
@@ -1687,7 +1767,10 @@
 
     @Override
     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
-        return CarrierInfoManager.getCarrierInfoForImsiEncryption(keyType, mContext);
+        String operatorNumeric = TelephonyManager.from(mContext)
+                .getSimOperatorNumericForPhone(mPhoneId);
+        return CarrierInfoManager.getCarrierInfoForImsiEncryption(keyType,
+                mContext, operatorNumeric);
     }
 
     @Override
@@ -1731,6 +1814,11 @@
     }
 
     @Override
+    public int getEmergencyNumberDbVersion() {
+        return getEmergencyNumberTracker().getEmergencyNumberDbVersion();
+    }
+
+    @Override
     public void resetCarrierKeysForImsiEncryption() {
         mCIM.resetCarrierKeysForImsiEncryption(mContext, mPhoneId);
     }
@@ -2397,6 +2485,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();
     }
 
@@ -2697,11 +2787,18 @@
                 }
                 break;
 
+            case EVENT_REGISTRATION_FAILED:
+                logd("Event RegistrationFailed Received");
+                ar = (AsyncResult) msg.obj;
+                RegistrationFailedEvent rfe = (RegistrationFailedEvent) ar.result;
+                mNotifier.notifyRegistrationFailed(this, rfe.cellIdentity, rfe.chosenPlmn,
+                        rfe.domain, rfe.causeCode, rfe.additionalCauseCode);
+                break;
+
             case EVENT_SET_CALL_FORWARD_DONE:
                 ar = (AsyncResult)msg.obj;
-                IccRecords r = mIccRecords.get();
                 Cfu cfu = (Cfu) ar.userObj;
-                if (ar.exception == null && r != null) {
+                if (ar.exception == null) {
                     setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
                 }
                 if (cfu.mOnComplete != null) {
@@ -2836,6 +2933,35 @@
                     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;
+                reapplyUiccAppsEnablementIfNeeded();
+                break;
+            }
+            case EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE: {
+                ar = (AsyncResult) msg.obj;
+                if (ar == null || ar.exception == null) return;
+                // TODO: b/146181737 don't throw exception and uncomment the retry below.
+                boolean expectedValue = (boolean) ar.userObj;
+                CommandException.Error error = ((CommandException) ar.exception).getCommandError();
+                throw new RuntimeException("Error received when re-applying uicc application"
+                        + " setting to " +  expectedValue + " on phone " + mPhoneId
+                        + " Error code: " + error);
+//                if (error == INTERNAL_ERR || error == SIM_BUSY) {
+//                    // Retry for certain errors, but not for others like RADIO_NOT_AVAILABLE or
+//                    // SIM_ABSENT, as they will trigger it whey they become available.
+//                    postDelayed(()->reapplyUiccAppsEnablementIfNeeded(), 1000);
+//                }
+//                break;
+            }
             default:
                 super.handleMessage(msg);
         }
@@ -2933,6 +3059,8 @@
                 updateDataConnectionTracker();
             }
         }
+
+        reapplyUiccAppsEnablementIfNeeded();
     }
 
     private void processIccRecordEvents(int eventCode) {
@@ -3008,20 +3136,17 @@
     }
 
     private void handleCfuQueryResult(CallForwardInfo[] infos) {
-        IccRecords r = mIccRecords.get();
-        if (r != null) {
-            if (infos == null || infos.length == 0) {
-                // Assume the default is not active
-                // Set unconditional CFF in SIM to false
-                setVoiceCallForwardingFlag(1, false, null);
-            } else {
-                for (int i = 0, s = infos.length; i < s; i++) {
-                    if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
-                        setVoiceCallForwardingFlag(1, (infos[i].status == 1),
-                            infos[i].number);
-                        // should only have the one
-                        break;
-                    }
+        if (infos == null || infos.length == 0) {
+            // Assume the default is not active
+            // Set unconditional CFF in SIM to false
+            setVoiceCallForwardingFlag(1, false, null);
+        } else {
+            for (int i = 0, s = infos.length; i < s; i++) {
+                if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
+                    setVoiceCallForwardingFlag(1, (infos[i].status == 1),
+                        infos[i].number);
+                    // should only have the one
+                    break;
                 }
             }
         }
@@ -3185,16 +3310,13 @@
             Rlog.d(LOG_TAG, "exitEmergencyCallbackMode: mImsPhone=" + mImsPhone
                     + " isPhoneTypeGsm=" + isPhoneTypeGsm());
         }
-        if (isPhoneTypeGsm()) {
-            if (mImsPhone != null) {
-                mImsPhone.exitEmergencyCallbackMode();
-            }
+        if (mImsPhone != null && mImsPhone.isInImsEcm()) {
+            mImsPhone.exitEmergencyCallbackMode();
         } else {
             if (mWakeLock.isHeld()) {
                 mWakeLock.release();
             }
-            // Send a message which will invoke handleExitEmergencyCallbackMode
-            mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
+            mCi.exitEmergencyCallbackMode(null);
         }
     }
 
@@ -3213,8 +3335,8 @@
 
             // Post this runnable so we will automatically exit
             // if no one invokes exitEmergencyCallbackMode() directly.
-            long delayInMillis = SystemProperties.getLong(
-                    TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+            long delayInMillis = TelephonyProperties.ecm_exit_timer()
+                    .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
             postDelayed(mExitEcmRunnable, delayInMillis);
             // We don't want to go to sleep while in Ecm
             mWakeLock.acquire();
@@ -3271,8 +3393,8 @@
                 mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
                 break;
             case RESTART_ECM_TIMER:
-                long delayInMillis = SystemProperties.getLong(
-                        TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+                long delayInMillis = TelephonyProperties.ecm_exit_timer()
+                        .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
                 postDelayed(mExitEcmRunnable, delayInMillis);
                 mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
                 break;
@@ -3478,6 +3600,11 @@
     }
 
     @Override
+    public int getOtasp() {
+        return mSST.getOtasp();
+    }
+
+    @Override
     public int getCdmaEriIconIndex() {
         if (isPhoneTypeGsm()) {
             return super.getCdmaEriIconIndex();
@@ -3527,8 +3654,8 @@
     private void phoneObjectUpdater(int newVoiceRadioTech) {
         logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
 
-        // Check for a voice over lte replacement
-        if (ServiceState.isLte(newVoiceRadioTech)
+        // Check for a voice over LTE/NR replacement
+        if (ServiceState.isPsOnlyTech(newVoiceRadioTech)
                 || (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
             CarrierConfigManager configMgr = (CarrierConfigManager)
                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -3652,9 +3779,11 @@
     }
 
     @Override
-    public void setSignalStrengthReportingCriteria(int[] thresholds, int ran) {
-        mCi.setSignalStrengthReportingCriteria(REPORTING_HYSTERESIS_MILLIS, REPORTING_HYSTERESIS_DB,
-                thresholds, ran, null);
+    public void setSignalStrengthReportingCriteria(
+            int signalStrengthMeasure, int[] thresholds, int ran, boolean isEnabled) {
+        mCi.setSignalStrengthReportingCriteria(new SignalThresholdInfo(signalStrengthMeasure,
+                REPORTING_HYSTERESIS_MILLIS, REPORTING_HYSTERESIS_DB, thresholds, isEnabled),
+                ran, null);
     }
 
     @Override
@@ -3827,7 +3956,8 @@
     private static final int[] VOICE_PS_CALL_RADIO_TECHNOLOGY = {
             ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
             ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA,
-            ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+            ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+            ServiceState.RIL_RADIO_TECHNOLOGY_NR
     };
 
     /**
@@ -3839,10 +3969,10 @@
      * @return the RIL voice radio technology used for CS calls,
      *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
      */
-    public @ServiceState.RilRadioTechnology int getCsCallRadioTech() {
+    public @RilRadioTechnology int getCsCallRadioTech() {
         int calcVrat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
         if (mSST != null) {
-            calcVrat = getCsCallRadioTech(mSST.mSS.getVoiceRegState(),
+            calcVrat = getCsCallRadioTech(mSST.mSS.getState(),
                     mSST.mSS.getRilVoiceRadioTechnology());
         }
 
@@ -3868,7 +3998,7 @@
      * @return the RIL voice radio technology used for CS calls,
      *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
      */
-    private @ServiceState.RilRadioTechnology int getCsCallRadioTech(int vrs, int vrat) {
+    private @RilRadioTechnology int getCsCallRadioTech(int vrs, int vrat) {
         logd("getCsCallRadioTech, current vrs=" + vrs + ", vrat=" + vrat);
         int calcVrat = vrat;
         if (vrs != ServiceState.STATE_IN_SERVICE
@@ -4027,4 +4157,55 @@
                 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF);
         updateUiTtyMode(ttyMode);
     }
+
+    private void reapplyUiccAppsEnablementIfNeeded() {
+        UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId);
+
+        // If no card is present or we don't have mUiccApplicationsEnabled yet, do nothing.
+        if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT
+                || mUiccApplicationsEnabled == null) {
+            return;
+        }
+
+        String iccId = slot.getIccId();
+        if (iccId == null) return;
+
+        SubscriptionInfo info = SubscriptionController.getInstance().getSubInfoForIccId(iccId);
+
+        // If info is null, it could be a new subscription. By default we enable it.
+        boolean expectedValue = info == null ? true : info.areUiccApplicationsEnabled();
+
+        // If for any reason current state is different from configured state, re-apply the
+        // configured state.
+        if (expectedValue != mUiccApplicationsEnabled) {
+            mCi.enableUiccApplications(expectedValue, Message.obtain(
+                    this, EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE, expectedValue));
+        }
+    }
+
+    // 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/HardwareConfig.java b/src/java/com/android/internal/telephony/HardwareConfig.java
index 8623354..cdce602 100644
--- a/src/java/com/android/internal/telephony/HardwareConfig.java
+++ b/src/java/com/android/internal/telephony/HardwareConfig.java
@@ -16,9 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.telephony.Rlog;
 import java.util.BitSet;
-import android.telephony.ServiceState;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/IccCard.java b/src/java/com/android/internal/telephony/IccCard.java
index d15c44c..b082516 100644
--- a/src/java/com/android/internal/telephony/IccCard.java
+++ b/src/java/com/android/internal/telephony/IccCard.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
diff --git a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index e619e61..a290c73 100644
--- a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -16,13 +16,12 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageManager;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.uicc.AdnRecord;
 import com.android.internal.telephony.uicc.AdnRecordCache;
@@ -30,6 +29,7 @@
 import com.android.internal.telephony.uicc.IccConstants;
 import com.android.internal.telephony.uicc.IccFileHandler;
 import com.android.internal.telephony.uicc.IccRecords;
+import com.android.telephony.Rlog;
 
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
diff --git a/src/java/com/android/internal/telephony/IccProvider.java b/src/java/com/android/internal/telephony/IccProvider.java
index ae5cd7b..76dc518 100644
--- a/src/java/com/android/internal/telephony/IccProvider.java
+++ b/src/java/com/android/internal/telephony/IccProvider.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentProvider;
 import android.content.ContentValues;
 import android.content.UriMatcher;
@@ -26,17 +26,16 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.uicc.AdnRecord;
 import com.android.internal.telephony.uicc.IccConstants;
+import com.android.telephony.Rlog;
 
 import java.util.List;
 
-
 /**
  * {@hide}
  */
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index c98d265..017cd95 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -21,11 +21,14 @@
 import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
 
 import android.Manifest;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
+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;
@@ -33,12 +36,15 @@
 import android.os.AsyncResult;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.UserManager;
 import android.provider.Telephony;
-import android.telephony.Rlog;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SmsCbMessage;
 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;
@@ -49,7 +55,10 @@
 import com.android.internal.telephony.uicc.IccConstants;
 import com.android.internal.telephony.uicc.IccFileHandler;
 import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.uicc.UiccProfile;
 import com.android.internal.util.HexDump;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -126,7 +135,7 @@
                             markMessagesAsRead((ArrayList<byte[]>) ar.result);
                         } else {
                             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
-                                log("Cannot load Sms records");
+                                loge("Cannot load Sms records");
                             }
                             mSms = null;
                         }
@@ -147,7 +156,7 @@
                         if (ar.exception == null) {
                             mSmsc = (String) ar.result;
                         } else {
-                            log("Cannot read SMSC");
+                            loge("Cannot read SMSC");
                             mSmsc = null;
                         }
                         mLock.notifyAll();
@@ -181,6 +190,31 @@
         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)) {
+                                new Thread(() -> {
+                                    log("Carrier config changed. Update ranges.");
+                                    mCellBroadcastRangeManager.updateRanges();
+                                }).start();
+                            }
+                        }
+                    }
+                }, new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+    }
+
+    private void enforceNotOnHandlerThread(String methodName) {
+        if (Looper.myLooper() == mHandler.getLooper()) {
+            throw new RuntimeException("This method " + methodName + " will deadlock if called from"
+                    + " the handler's thread.");
+        }
     }
 
     protected void markMessagesAsRead(ArrayList<byte[]> messages) {
@@ -194,7 +228,7 @@
             //shouldn't really happen, as messages are marked as read, only
             //after importing it from icc.
             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
-                log("markMessagesAsRead - aborting, no icc card present.");
+                loge("markMessagesAsRead - aborting, no icc card present.");
             }
             return;
         }
@@ -243,6 +277,7 @@
                 " status=" + status + " ==> " +
                 "("+ Arrays.toString(pdu) + ")");
         enforceReceiveAndSend("Updating message on Icc");
+        enforceNotOnHandlerThread("updateMessageOnIccEf");
         if (mAppOps.noteOp(AppOpsManager.OPSTR_WRITE_ICC_SMS, Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
             return false;
@@ -276,20 +311,24 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to update by index");
+                loge("interrupted while trying to update by index");
             }
         }
         return mSuccess;
     }
 
     /**
-     * Copy a raw SMS PDU to the Icc.
+     * Copies a raw SMS PDU to the ICC.
      *
-     * @param pdu the raw PDU to store
-     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
-     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
-     * @return success or not
-     *
+     * @param callingPackage the package name of the calling app.
+     * @param status message status. One of these status:
+     *               <code>STATUS_ON_ICC_READ</code>
+     *               <code>STATUS_ON_ICC_UNREAD</code>
+     *               <code>STATUS_ON_ICC_SENT</code>
+     *               <code>STATUS_ON_ICC_UNSENT</code>
+     * @param pdu the raw PDU to store.
+     * @param smsc the SMSC for this message. Null means use default.
+     * @return true for success. Otherwise false.
      */
     @UnsupportedAppUsage
     public boolean copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc) {
@@ -298,6 +337,7 @@
                 "pdu=("+ Arrays.toString(pdu) +
                 "), smsc=(" + Arrays.toString(smsc) +")");
         enforceReceiveAndSend("Copying message to Icc");
+        enforceNotOnHandlerThread("copyMessageToIccEf");
         if (mAppOps.noteOp(AppOpsManager.OPSTR_WRITE_ICC_SMS, Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
             return false;
@@ -317,7 +357,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to update by index");
+                loge("interrupted while trying to update by index");
             }
         }
         return mSuccess;
@@ -336,6 +376,7 @@
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.RECEIVE_SMS,
                 "Reading messages from Icc");
+        enforceNotOnHandlerThread("getAllMessagesFromIccEf");
         if (mAppOps.noteOp(AppOpsManager.OPSTR_READ_ICC_SMS, Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
             return new ArrayList<SmsRawData>();
@@ -344,7 +385,7 @@
 
             IccFileHandler fh = mPhone.getIccFileHandler();
             if (fh == null) {
-                Rlog.e(LOG_TAG, "Cannot load Sms records. No icc card?");
+                loge("Cannot load Sms records. No icc card?");
                 mSms = null;
                 return mSms;
             }
@@ -355,7 +396,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to load from the Icc");
+                loge("interrupted while trying to load from the Icc");
             }
         }
         return mSms;
@@ -610,7 +651,7 @@
                         try {
                             receivedIntent.send(result);
                         } catch (PendingIntent.CanceledException e) {
-                            Rlog.d(LOG_TAG, "receivedIntent cancelled.");
+                            loge("receivedIntent cancelled.");
                         }
                     }
                 }
@@ -832,6 +873,7 @@
                 callingPackage, "getSmscAddressFromIccEf")) {
             return null;
         }
+        enforceNotOnHandlerThread("getSmscAddressFromIccEf");
         synchronized (mLock) {
             mSmsc = null;
             Message response = mHandler.obtainMessage(EVENT_GET_SMSC_DONE);
@@ -839,7 +881,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to read SMSC");
+                loge("interrupted while trying to read SMSC");
             }
         }
         return mSmsc;
@@ -863,7 +905,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to write SMSC");
+                loge("interrupted while trying to write SMSC");
             }
         }
         return mSuccess;
@@ -881,9 +923,9 @@
         mContext.enforceCallingPermission("android.permission.RECEIVE_EMERGENCY_BROADCAST",
                 "enabling cell broadcast range [" + startMessageId + "-" + endMessageId + "]. "
                         + "ranType=" + ranType);
-        if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM) {
+        if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) {
             return enableGsmBroadcastRange(startMessageId, endMessageId);
-        } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA) {
+        } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2) {
             return enableCdmaBroadcastRange(startMessageId, endMessageId);
         } else {
             throw new IllegalArgumentException("Not a supported RAN Type");
@@ -894,9 +936,9 @@
         mContext.enforceCallingPermission("android.permission.RECEIVE_EMERGENCY_BROADCAST",
                 "disabling cell broadcast range [" + startMessageId + "-" + endMessageId
                         + "]. ranType=" + ranType);
-        if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM ) {
+        if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) {
             return disableGsmBroadcastRange(startMessageId, endMessageId);
-        } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA)  {
+        } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2)  {
             return disableCdmaBroadcastRange(startMessageId, endMessageId);
         } else {
             throw new IllegalArgumentException("Not a supported RAN Type");
@@ -1107,9 +1149,10 @@
 
     @UnsupportedAppUsage
     private boolean setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs) {
-        if (DBG)
+        if (DBG) {
             log("Calling setGsmBroadcastConfig with " + configs.length + " configurations");
-
+        }
+        enforceNotOnHandlerThread("setCellBroadcastConfig");
         synchronized (mLock) {
             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
 
@@ -1119,7 +1162,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to set cell broadcast config");
+                loge("interrupted while trying to set cell broadcast config");
             }
         }
 
@@ -1127,9 +1170,11 @@
     }
 
     private boolean setCellBroadcastActivation(boolean activate) {
-        if (DBG)
+        if (DBG) {
             log("Calling setCellBroadcastActivation(" + activate + ')');
+        }
 
+        enforceNotOnHandlerThread("setCellBroadcastConfig");
         synchronized (mLock) {
             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
 
@@ -1139,7 +1184,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to set cell broadcast activation");
+                loge("interrupted while trying to set cell broadcast activation");
             }
         }
 
@@ -1148,9 +1193,11 @@
 
     @UnsupportedAppUsage
     private boolean setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs) {
-        if (DBG)
+        if (DBG) {
             log("Calling setCdmaBroadcastConfig with " + configs.length + " configurations");
+        }
 
+        enforceNotOnHandlerThread("setCdmaBroadcastConfig");
         synchronized (mLock) {
             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
 
@@ -1160,7 +1207,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to set cdma broadcast config");
+                loge("interrupted while trying to set cdma broadcast config");
             }
         }
 
@@ -1168,9 +1215,11 @@
     }
 
     private boolean setCdmaBroadcastActivation(boolean activate) {
-        if (DBG)
+        if (DBG) {
             log("Calling setCdmaBroadcastActivation(" + activate + ")");
+        }
 
+        enforceNotOnHandlerThread("setCdmaBroadcastActivation");
         synchronized (mLock) {
             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
 
@@ -1180,7 +1229,7 @@
             try {
                 mLock.wait();
             } catch (InterruptedException e) {
-                log("interrupted while trying to set cdma broadcast activation");
+                loge("interrupted while trying to set cdma broadcast activation");
             }
         }
 
@@ -1189,7 +1238,15 @@
 
     @UnsupportedAppUsage
     protected void log(String msg) {
-        Log.d(LOG_TAG, "[IccSmsInterfaceManager] " + msg);
+        Rlog.d(LOG_TAG, msg);
+    }
+
+    protected void loge(String msg) {
+        Rlog.e(LOG_TAG, msg);
+    }
+
+    protected void loge(String msg, Throwable e) {
+        Rlog.e(LOG_TAG, msg, e);
     }
 
     @UnsupportedAppUsage
@@ -1215,13 +1272,13 @@
         }
         final ContentResolver resolver = mContext.getContentResolver();
         if (!isFailedOrDraft(resolver, messageUri)) {
-            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: not FAILED or DRAFT message");
+            loge("sendStoredText: not FAILED or DRAFT message");
             returnUnspecifiedFailure(sentIntent);
             return;
         }
         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
         if (textAndAddress == null) {
-            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: can not load text");
+            loge("sendStoredText: can not load text");
             returnUnspecifiedFailure(sentIntent);
             return;
         }
@@ -1242,20 +1299,19 @@
         }
         final ContentResolver resolver = mContext.getContentResolver();
         if (!isFailedOrDraft(resolver, messageUri)) {
-            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: "
-                    + "not FAILED or DRAFT message");
+            loge("sendStoredMultipartText: not FAILED or DRAFT message");
             returnUnspecifiedFailure(sentIntents);
             return;
         }
         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
         if (textAndAddress == null) {
-            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not load text");
+            loge("sendStoredMultipartText: can not load text");
             returnUnspecifiedFailure(sentIntents);
             return;
         }
         final ArrayList<String> parts = SmsManager.getDefault().divideMessage(textAndAddress[0]);
         if (parts == null || parts.size() < 1) {
-            Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not divide text");
+            loge("sendStoredMultipartText: can not divide text");
             returnUnspecifiedFailure(sentIntents);
             return;
         }
@@ -1308,6 +1364,28 @@
                 SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
     }
 
+    public int getSmsCapacityOnIcc() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+                "getSmsCapacityOnIcc");
+
+        int numberOnIcc = 0;
+        if (mPhone.getIccRecordsLoaded()) {
+            final UiccProfile uiccProfile = UiccController.getInstance()
+                    .getUiccProfileForPhone(mPhone.getPhoneId());
+            if(uiccProfile != null) {
+                numberOnIcc = uiccProfile.getIccRecords().getSmsCapacityOnIcc();
+            } else {
+                loge("uiccProfile is null");
+            }
+        } else {
+            loge("getSmsCapacityOnIcc - aborting, no icc card present.");
+        }
+
+        log("getSmsCapacityOnIcc().numberOnIcc = " + numberOnIcc);
+        return numberOnIcc;
+    }
+
     private boolean isFailedOrDraft(ContentResolver resolver, Uri messageUri) {
         // Clear the calling identity and query the database using the phone user id
         // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
@@ -1327,7 +1405,7 @@
                         || type == Telephony.Sms.MESSAGE_TYPE_FAILED;
             }
         } catch (SQLiteException e) {
-            Log.e(LOG_TAG, "[IccSmsInterfaceManager]isFailedOrDraft: query message type failed", e);
+            loge("isFailedOrDraft: query message type failed", e);
         } finally {
             if (cursor != null) {
                 cursor.close();
@@ -1358,7 +1436,7 @@
                 return new String[]{ cursor.getString(0), cursor.getString(1) };
             }
         } catch (SQLiteException e) {
-            Log.e(LOG_TAG, "[IccSmsInterfaceManager]loadText: query message text failed", e);
+            loge("loadText: query message text failed", e);
         } finally {
             if (cursor != null) {
                 cursor.close();
diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
index 4be189d..a14db4e 100644
--- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
@@ -23,7 +23,6 @@
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.RegistrationManager;
@@ -41,6 +40,7 @@
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.util.SMSDispatcherUtil;
+import com.android.telephony.Rlog;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -235,14 +235,9 @@
     public ImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) {
         super(phone, smsDispatchersController);
 
-        mImsManagerConnector = new FeatureConnector<ImsManager>(mContext, mPhone.getPhoneId(),
+        mImsManagerConnector = new FeatureConnector<>(mContext, mPhone.getPhoneId(),
                 new FeatureConnector.Listener<ImsManager>() {
                     @Override
-                    public boolean isSupported() {
-                        return ImsManager.isImsSupportedOnDevice(mContext);
-                    }
-
-                    @Override
                     public ImsManager getFeatureManager() {
                         return ImsManager.getInstance(mContext, phone.getPhoneId());
                     }
@@ -275,9 +270,9 @@
     }
 
     private boolean isLteService() {
-        return ((mPhone.getServiceState().getRilVoiceRadioTechnology() ==
+        return ((mPhone.getServiceState().getRilDataRadioTechnology() ==
             ServiceState.RIL_RADIO_TECHNOLOGY_LTE) && (mPhone.getServiceState().
-                getState() == ServiceState.STATE_IN_SERVICE));
+                getDataRegistrationState() == ServiceState.STATE_IN_SERVICE));
     }
 
     private boolean isLimitedLteService() {
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index 3d66b60..1c6cd4fa 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -19,7 +19,6 @@
 import static android.service.carrier.CarrierMessagingService.RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE;
 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
@@ -27,6 +26,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -35,12 +35,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.IDeviceIdleController;
 import android.os.Message;
@@ -51,7 +51,6 @@
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.service.carrier.CarrierMessagingService;
-import android.telephony.Rlog;
 import android.telephony.SmsMessage;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -64,9 +63,11 @@
 import com.android.internal.telephony.SmsConstants.MessageClass;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.util.NotificationChannelController;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.HexDump;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.telephony.Rlog;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
@@ -224,9 +225,6 @@
     protected Phone mPhone;
 
     @UnsupportedAppUsage
-    protected CellBroadcastHandler mCellBroadcastHandler;
-
-    @UnsupportedAppUsage
     private UserManager mUserManager;
 
     protected TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
@@ -236,8 +234,6 @@
     @UnsupportedAppUsage
     IDeviceIdleController mDeviceIdleController;
 
-    protected static boolean sEnableCbModule = false;
-
     protected CellBroadcastServiceManager mCellBroadcastServiceManager;
 
     // Delete permanently from raw table
@@ -262,13 +258,12 @@
      * @param storageMonitor the SmsStorageMonitor to check for storage availability
      */
     protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor,
-            Phone phone, CellBroadcastHandler cellBroadcastHandler) {
+            Phone phone) {
         super(name);
 
         mContext = context;
         mStorageMonitor = storageMonitor;
         mPhone = phone;
-        mCellBroadcastHandler = cellBroadcastHandler;
         mResolver = context.getContentResolver();
         mWapPush = new WapPushOverSms(context);
 
@@ -332,7 +327,7 @@
                 default: {
                     String errorText = "processMessage: unhandled message type " + msg.what +
                         " currState=" + getCurrentState().getName();
-                    if (Build.IS_DEBUGGABLE) {
+                    if (TelephonyUtils.IS_DEBUGGABLE) {
                         loge("---- Dumping InboundSmsHandler ----");
                         loge("Total records=" + getLogRecCount());
                         for (int i = Math.max(getLogRecSize() - 20, 0); i < getLogRecSize(); i++) {
@@ -1124,7 +1119,7 @@
      * @param user user to deliver the intent to
      */
     @UnsupportedAppUsage
-    public void dispatchIntent(Intent intent, String permission, int appOp,
+    public void dispatchIntent(Intent intent, String permission, String appOp,
             Bundle opts, BroadcastReceiver resultReceiver, UserHandle user, int subId) {
         intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
         final String action = intent.getAction();
@@ -1165,7 +1160,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
@@ -1174,16 +1169,32 @@
                     }
                 }
                 // Only pass in the resultReceiver when the USER_SYSTEM is processed.
-                mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts,
-                        users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null,
-                        getHandler(), Activity.RESULT_OK, null, null);
+                try {
+                    mContext.createPackageContextAsUser(mContext.getPackageName(), 0, targetUser)
+                            .sendOrderedBroadcast(intent, permission, appOp, opts,
+                                    users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null,
+                                    getHandler(), Activity.RESULT_OK, null /* initialData */,
+                                    null /* initialExtras */);
+                } catch (PackageManager.NameNotFoundException ignored) {
+                }
             }
         } else {
-            mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts,
-                    resultReceiver, getHandler(), Activity.RESULT_OK, null, null);
+            try {
+                mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user)
+                        .sendOrderedBroadcast(intent, permission, appOp, opts, resultReceiver,
+                                getHandler(), Activity.RESULT_OK, null /* initialData */,
+                                null /* initialExtras */);
+            } catch (PackageManager.NameNotFoundException ignored) {
+            }
         }
     }
 
+    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.
      */
@@ -1278,7 +1289,7 @@
 
         Bundle options = handleSmsWhitelisting(intent.getComponent(), isClass0);
         dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
-                AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM, subId);
+                AppOpsManager.OPSTR_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM, subId);
     }
 
     /**
@@ -1465,7 +1476,7 @@
                 Bundle options = handleSmsWhitelisting(null, false /* bgActivityStartAllowed */);
 
                 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
-                        AppOpsManager.OP_RECEIVE_SMS,
+                        AppOpsManager.OPSTR_RECEIVE_SMS,
                         options, this, UserHandle.ALL, subId);
             } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) {
                 // Now dispatch the notification only intent
@@ -1488,7 +1499,7 @@
 
                 String mimeType = intent.getType();
                 dispatchIntent(intent, WapPushOverSms.getPermissionForType(mimeType),
-                        WapPushOverSms.getAppOpsPermissionForIntent(mimeType), options, this,
+                        WapPushOverSms.getAppOpsStringPermissionForIntent(mimeType), options, this,
                         UserHandle.SYSTEM, subId);
             } else {
                 // Now that the intents have been deleted we can clean up the PDU data.
@@ -1701,9 +1712,6 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         super.dump(fd, pw, args);
-        if (mCellBroadcastHandler != null) {
-            mCellBroadcastHandler.dump(fd, pw, args);
-        }
         if (mCellBroadcastServiceManager != null) {
             mCellBroadcastServiceManager.dump(fd, pw, args);
         }
@@ -1790,15 +1798,11 @@
     protected abstract class CbTestBroadcastReceiver extends BroadcastReceiver {
 
         protected abstract void handleTestAction(Intent intent);
-        protected abstract void handleToggleEnable();
-        protected abstract void handleToggleDisable(Context context);
 
         protected final String mTestAction;
-        protected final String mToggleAction;
 
-        public CbTestBroadcastReceiver(String testAction, String toggleAction) {
+        public CbTestBroadcastReceiver(String testAction) {
             mTestAction = testAction;
-            mToggleAction = toggleAction;
         }
 
         @Override
@@ -1812,19 +1816,6 @@
                     return;
                 }
                 handleTestAction(intent);
-            } else if (intent.getAction().equals(mToggleAction)) {
-                if (intent.hasExtra("enable")) {
-                    sEnableCbModule = intent.getBooleanExtra("enable", false);
-                } else {
-                    sEnableCbModule = !sEnableCbModule;
-                }
-                if (sEnableCbModule) {
-                    log("enabling CB module");
-                    handleToggleEnable();
-                } else {
-                    log("enabling legacy platform CB handling");
-                    handleToggleDisable(context);
-                }
             }
         }
     }
diff --git a/src/java/com/android/internal/telephony/InboundSmsTracker.java b/src/java/com/android/internal/telephony/InboundSmsTracker.java
index 4d9971e..30f63b2 100644
--- a/src/java/com/android/internal/telephony/InboundSmsTracker.java
+++ b/src/java/com/android/internal/telephony/InboundSmsTracker.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.util.Pair;
diff --git a/src/java/com/android/internal/telephony/IntRangeManager.java b/src/java/com/android/internal/telephony/IntRangeManager.java
index b82a20e..02880e0 100644
--- a/src/java/com/android/internal/telephony/IntRangeManager.java
+++ b/src/java/com/android/internal/telephony/IntRangeManager.java
@@ -16,7 +16,8 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 
diff --git a/src/java/com/android/internal/telephony/IntentBroadcaster.java b/src/java/com/android/internal/telephony/IntentBroadcaster.java
index e211c24..e1dca63 100644
--- a/src/java/com/android/internal/telephony/IntentBroadcaster.java
+++ b/src/java/com/android/internal/telephony/IntentBroadcaster.java
@@ -51,7 +51,7 @@
                     while (iterator.hasNext()) {
                         Map.Entry pair = (Map.Entry) iterator.next();
                         Intent i = (Intent) pair.getValue();
-                        i.putExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, true);
+                        i.putExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, true);
                         iterator.remove();
                         logd("Rebroadcasting intent " + i.getAction() + " "
                                 + i.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index 1c9a7e0..704e09e 100755
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -26,15 +26,14 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.AsyncResult;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.sysprop.TelephonyProperties;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
 import android.telephony.CellInfoLte;
 import android.telephony.CellInfoWcdma;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -42,10 +41,14 @@
 import android.util.LocalLog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.MccTable.MccMnc;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -57,7 +60,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;
@@ -124,6 +126,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;
@@ -240,10 +244,11 @@
         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);
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             filter.addAction(ACTION_COUNTRY_OVERRIDE);
         }
         mPhone.getContext().registerReceiver(mBroadcastReceiver, filter);
@@ -282,23 +287,16 @@
     private String getMccFromCellInfo() {
         String selectedMcc = null;
         if (mCellInfoList != null) {
-            Map<String, Integer> countryCodeMap = new HashMap<>();
+            Map<String, Integer> mccMap = new HashMap<>();
             int maxCount = 0;
             for (CellInfo cellInfo : mCellInfoList) {
-                String mcc = null;
-                if (cellInfo instanceof CellInfoGsm) {
-                    mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMccString();
-                } else if (cellInfo instanceof CellInfoLte) {
-                    mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMccString();
-                } else if (cellInfo instanceof CellInfoWcdma) {
-                    mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMccString();
-                }
+                String mcc = getNetworkMcc(cellInfo);
                 if (mcc != null) {
                     int count = 1;
-                    if (countryCodeMap.containsKey(mcc)) {
-                        count = countryCodeMap.get(mcc) + 1;
+                    if (mccMap.containsKey(mcc)) {
+                        count = mccMap.get(mcc) + 1;
                     }
-                    countryCodeMap.put(mcc, count);
+                    mccMap.put(mcc, count);
                     // This is unlikely, but if MCC from cell info looks different, we choose the
                     // MCC that occurs most.
                     if (count > maxCount) {
@@ -312,6 +310,70 @@
     }
 
     /**
+     * Get the most frequent MCC + MNC combination with the specified MCC using cell tower
+     * information. If no one combination is more frequent than any other an arbitrary MCC + MNC is
+     * returned with the matching MCC. The MNC value returned can be null if it is not provided by
+     * the cell tower information.
+     *
+     * @param mccToMatch the MCC to match
+     * @return a matching {@link MccMnc}. Null if the information is not available.
+     */
+    @Nullable
+    private MccMnc getMccMncFromCellInfo(@NonNull String mccToMatch) {
+        MccMnc selectedMccMnc = null;
+        if (mCellInfoList != null) {
+            Map<MccMnc, Integer> mccMncMap = new HashMap<>();
+            int maxCount = 0;
+            for (CellInfo cellInfo : mCellInfoList) {
+                String mcc = getNetworkMcc(cellInfo);
+                if (Objects.equals(mcc, mccToMatch)) {
+                    String mnc = getNetworkMnc(cellInfo);
+                    MccMnc mccMnc = new MccMnc(mcc, mnc);
+                    int count = 1;
+                    if (mccMncMap.containsKey(mccMnc)) {
+                        count = mccMncMap.get(mccMnc) + 1;
+                    }
+                    mccMncMap.put(mccMnc, count);
+                    // We keep track of the MCC+MNC combination that occurs most frequently, if
+                    // there is one. A null MNC is treated like any other distinct MCC+MNC
+                    // combination.
+                    if (count > maxCount) {
+                        maxCount = count;
+                        selectedMccMnc = mccMnc;
+                    }
+                }
+            }
+        }
+        return selectedMccMnc;
+    }
+
+    @Nullable
+    private static String getNetworkMcc(CellInfo cellInfo) {
+        String mccString = null;
+        if (cellInfo instanceof CellInfoGsm) {
+            mccString = ((CellInfoGsm) cellInfo).getCellIdentity().getMccString();
+        } else if (cellInfo instanceof CellInfoLte) {
+            mccString = ((CellInfoLte) cellInfo).getCellIdentity().getMccString();
+        } else if (cellInfo instanceof CellInfoWcdma) {
+            mccString = ((CellInfoWcdma) cellInfo).getCellIdentity().getMccString();
+        }
+        return mccString;
+    }
+
+    @Nullable
+    private static String getNetworkMnc(CellInfo cellInfo) {
+        String mccString = null;
+        if (cellInfo instanceof CellInfoGsm) {
+            mccString = ((CellInfoGsm) cellInfo).getCellIdentity().getMncString();
+        } else if (cellInfo instanceof CellInfoLte) {
+            mccString = ((CellInfoLte) cellInfo).getCellIdentity().getMncString();
+        } else if (cellInfo instanceof CellInfoWcdma) {
+            mccString = ((CellInfoWcdma) cellInfo).getCellIdentity().getMncString();
+        }
+        return mccString;
+    }
+
+    /**
      * Called when SIM card state changed. Only when we absolutely know the SIM is absent, we get
      * cell info from the network. Other SIM states like NOT_READY might be just a transitioning
      * state.
@@ -457,15 +519,23 @@
         String countryIso = getCarrierCountry();
         String countryIsoDebugInfo = "getCarrierCountry()";
 
+        // For time zone detection we want the best geographical match we can get, which may differ
+        // from the countryIso.
+        String timeZoneCountryIso = null;
+        String timeZoneCountryIsoDebugInfo = null;
+
         if (!TextUtils.isEmpty(mOperatorNumeric)) {
-            try {
-                String mcc = mOperatorNumeric.substring(0, 3);
-                countryIso = MccTable.countryCodeForMcc(mcc);
+            MccMnc mccMnc = MccMnc.fromOperatorNumeric(mOperatorNumeric);
+            if (mccMnc != null) {
+                countryIso = MccTable.countryCodeForMcc(mccMnc.mcc);
                 countryIsoDebugInfo = "OperatorNumeric(" + mOperatorNumeric
-                        + "): MccTable.countryCodeForMcc(\"" + mcc + "\")";
-            } catch (StringIndexOutOfBoundsException ex) {
+                        + "): MccTable.countryCodeForMcc(\"" + mccMnc.mcc + "\")";
+                timeZoneCountryIso = MccTable.geoCountryCodeForMccMnc(mccMnc);
+                timeZoneCountryIsoDebugInfo =
+                        "OperatorNumeric: MccTable.geoCountryCodeForMccMnc(" + mccMnc + ")";
+            } else {
                 loge("updateLocale: Can't get country from operator numeric. mOperatorNumeric = "
-                        + mOperatorNumeric + ". ex=" + ex);
+                        + mOperatorNumeric);
             }
         }
 
@@ -473,28 +543,44 @@
         // info.
         if (TextUtils.isEmpty(countryIso)) {
             String mcc = getMccFromCellInfo();
-            countryIso = MccTable.countryCodeForMcc(mcc);
-            countryIsoDebugInfo = "CellInfo: MccTable.countryCodeForMcc(\"" + mcc + "\")";
+            if (mcc != null) {
+                countryIso = MccTable.countryCodeForMcc(mcc);
+                countryIsoDebugInfo = "CellInfo: MccTable.countryCodeForMcc(\"" + mcc + "\")";
+
+                MccMnc mccMnc = getMccMncFromCellInfo(mcc);
+                if (mccMnc != null) {
+                    timeZoneCountryIso = MccTable.geoCountryCodeForMccMnc(mccMnc);
+                    timeZoneCountryIsoDebugInfo =
+                            "CellInfo: MccTable.geoCountryCodeForMccMnc(" + mccMnc + ")";
+                }
+            }
         }
 
         if (mCountryOverride != null) {
             countryIso = mCountryOverride;
             countryIsoDebugInfo = "mCountryOverride = \"" + mCountryOverride + "\"";
-            log("Override current country to " + mCountryOverride);
+            timeZoneCountryIso = countryIso;
+            timeZoneCountryIsoDebugInfo = countryIsoDebugInfo;
         }
 
         log("updateLocale: countryIso = " + countryIso
                 + ", countryIsoDebugInfo = " + countryIsoDebugInfo);
         if (!Objects.equals(countryIso, mCurrentCountryIso)) {
-            String msg = "updateLocale: Change the current country to \"" + countryIso
-                    + "\", countryIsoDebugInfo = " + countryIsoDebugInfo
+            String msg = "updateLocale: Change the current country to \"" + countryIso + "\""
+                    + ", countryIsoDebugInfo = " + countryIsoDebugInfo
                     + ", mCellInfoList = " + mCellInfoList;
             log(msg);
             mLocalLog.log(msg);
             mCurrentCountryIso = countryIso;
 
-            TelephonyManager.setTelephonyProperty(mPhone.getPhoneId(),
-                    TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, mCurrentCountryIso);
+            int phoneId = mPhone.getPhoneId();
+            if (SubscriptionManager.isValidPhoneId(phoneId)) {
+                List<String> newProp = new ArrayList<>(
+                        TelephonyProperties.operator_iso_country());
+                while (newProp.size() <= phoneId) newProp.add(null);
+                newProp.set(phoneId, mCurrentCountryIso);
+                TelephonyProperties.operator_iso_country(newProp);
+            }
 
             Intent intent = new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
             intent.putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, countryIso);
@@ -502,19 +588,30 @@
             mPhone.getContext().sendBroadcast(intent);
         }
 
-        // For a test cell, the NitzStateMachine requires handleCountryDetected("") to pass
-        // compliance tests. http://b/142840879
+        // Pass the geographical country information to the telephony time zone detection code.
+
         boolean isTestMcc = false;
         if (!TextUtils.isEmpty(mOperatorNumeric)) {
+            // For a test cell (MCC 001), the NitzStateMachine requires handleCountryDetected("") in
+            // order to pass compliance tests. http://b/142840879
             if (mOperatorNumeric.startsWith("001")) {
                 isTestMcc = true;
-                countryIso = "";
+                timeZoneCountryIso = "";
+                timeZoneCountryIsoDebugInfo = "Test cell: " + mOperatorNumeric;
             }
         }
-        if (TextUtils.isEmpty(countryIso) && !isTestMcc) {
+        if (timeZoneCountryIso == null) {
+            // After this timeZoneCountryIso may still be null.
+            timeZoneCountryIso = countryIso;
+            timeZoneCountryIsoDebugInfo = "Defaulted: " + countryIsoDebugInfo;
+        }
+        log("updateLocale: timeZoneCountryIso = " + timeZoneCountryIso
+                + ", timeZoneCountryIsoDebugInfo = " + timeZoneCountryIsoDebugInfo);
+
+        if (TextUtils.isEmpty(timeZoneCountryIso) && !isTestMcc) {
             mNitzStateMachine.handleCountryUnavailable();
         } else {
-            mNitzStateMachine.handleCountryDetected(countryIso);
+            mNitzStateMachine.handleCountryDetected(timeZoneCountryIso);
         }
     }
 
@@ -524,11 +621,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);
     }
 
     /**
@@ -540,7 +637,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 31b8d0a..1492402 100644
--- a/src/java/com/android/internal/telephony/MccTable.java
+++ b/src/java/com/android/internal/telephony/MccTable.java
@@ -16,27 +16,31 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.icu.util.ULocale;
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.text.TextUtils;
-import android.util.Slog;
+import android.timezone.TelephonyLookup;
+import android.timezone.TelephonyNetwork;
+import android.timezone.TelephonyNetworkFinder;
 
-import com.android.internal.app.LocaleStore;
-import com.android.internal.app.LocaleStore.LocaleInfo;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Mobile Country Code
@@ -46,23 +50,30 @@
 public final class MccTable {
     static final String LOG_TAG = "MccTable";
 
+    @GuardedBy("MccTable.class")
+    private static TelephonyNetworkFinder sTelephonyNetworkFinder;
+
     static ArrayList<MccEntry> sTable;
 
-    static class MccEntry implements Comparable<MccEntry> {
+    /**
+     * Container class for mcc and iso. This class implements compareTo so that it can be sorted
+     * by mcc.
+     */
+    public static class MccEntry implements Comparable<MccEntry> {
         final int mMcc;
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
                 publicAlternatives = "There is no alternative for {@code MccTable.MccEntry.mIso}, "
                         + "but it was included in hidden APIs due to a static analysis false "
                         + "positive and has been made greylist-max-q. Please file a bug if you "
                         + "still require this API.")
-        final String mIso;
+        public final String mIso;
         final int mSmallestDigitsMnc;
 
-        MccEntry(int mnc, String iso, int smallestDigitsMCC) {
+        MccEntry(int mcc, String iso, int smallestDigitsMCC) {
             if (iso == null) {
                 throw new NullPointerException();
             }
-            mMcc = mnc;
+            mMcc = mcc;
             mIso = iso;
             mSmallestDigitsMnc = smallestDigitsMCC;
         }
@@ -73,12 +84,83 @@
         }
     }
 
+    /**
+     * A combination of MCC and MNC. The MNC is optional and may be null.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static class MccMnc {
+        @NonNull
+        public final String mcc;
+
+        @Nullable
+        public final String mnc;
+
+        /**
+         * Splits the supplied String in two: the first three characters are treated as the MCC,
+         * the remaining characters are treated as the MNC.
+         */
+        @Nullable
+        public static MccMnc fromOperatorNumeric(@NonNull String operatorNumeric) {
+            Objects.requireNonNull(operatorNumeric);
+            String mcc;
+            try {
+                mcc = operatorNumeric.substring(0, 3);
+            } catch (StringIndexOutOfBoundsException e) {
+                return null;
+            }
+
+            String mnc;
+            try {
+                mnc = operatorNumeric.substring(3);
+            } catch (StringIndexOutOfBoundsException e) {
+                mnc = null;
+            }
+            return new MccMnc(mcc, mnc);
+        }
+
+        /**
+         * Creates an MccMnc using the supplied values.
+         */
+        public MccMnc(@NonNull String mcc, @Nullable String mnc) {
+            this.mcc = Objects.requireNonNull(mcc);
+            this.mnc = mnc;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            MccMnc mccMnc = (MccMnc) o;
+            return mcc.equals(mccMnc.mcc)
+                    && Objects.equals(mnc, mccMnc.mnc);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mcc, mnc);
+        }
+
+        @Override
+        public String toString() {
+            return "MccMnc{"
+                    + "mcc='" + mcc + '\''
+                    + ", mnc='" + mnc + '\''
+                    + '}';
+        }
+    }
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
             publicAlternatives = "There is no alternative for {@code MccTable.entryForMcc}, "
                     + "but it was included in hidden APIs due to a static analysis false positive "
                     + "and has been made greylist-max-q. Please file a bug if you still require "
                     + "this API.")
-    private static MccEntry entryForMcc(int mcc) {
+    public static MccEntry entryForMcc(int mcc) {
         MccEntry m = new MccEntry(mcc, "", 0);
 
         int index = Collections.binarySearch(sTable, m);
@@ -91,11 +173,11 @@
     }
 
     /**
-     * Given a GSM Mobile Country Code, returns
-     * an ISO two-character country code if available.
-     * Returns "" if unavailable.
+     * Given a GSM Mobile Country Code, returns a lower-case ISO 3166 alpha-2 country code if
+     * available. Returns empty string if unavailable.
      */
     @UnsupportedAppUsage
+    @NonNull
     public static String countryCodeForMcc(int mcc) {
         MccEntry entry = entryForMcc(mcc);
 
@@ -107,11 +189,11 @@
     }
 
     /**
-     * Given a GSM Mobile Country Code, returns
-     * an ISO two-character country code if available.
-     * Returns empty string if unavailable.
+     * Given a GSM Mobile Country Code, returns a lower-case ISO 3166 alpha-2 country code if
+     * available. Returns empty string if unavailable.
      */
-    public static String countryCodeForMcc(String mcc) {
+    @NonNull
+    public static String countryCodeForMcc(@NonNull String mcc) {
         try {
             return countryCodeForMcc(Integer.parseInt(mcc));
         } catch (NumberFormatException ex) {
@@ -120,37 +202,51 @@
     }
 
     /**
-     * Given a GSM Mobile Country Code, returns
-     * an ISO 2-3 character language code if available.
-     * Returns null if unavailable.
+     * Given a combination of MCC and MNC, returns a lower case ISO 3166 alpha-2 country code for
+     * the device's geographical location.
+     *
+     * <p>This can give a better geographical result than {@link #countryCodeForMcc(String)}
+     * (which provides the official "which country is the MCC assigned to?" answer) for cases when
+     * MNC is also available: Sometimes an MCC can be used by multiple countries and the MNC can
+     * help distinguish, or the MCC assigned to a country isn't used for geopolitical reasons.
+     * When the geographical country is needed  (e.g. time zone detection) this version can provide
+     * more pragmatic results than the official MCC-only answer. This method falls back to calling
+     * {@link #countryCodeForMcc(int)} if no special MCC+MNC cases are found.
+     * Returns empty string if no code can be determined.
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
-            publicAlternatives = "There is no alternative for {@code MccTable.defaultLanguageForMcc"
-                    + "}, but it was included in hidden APIs due to a static analysis false "
-                    + "positive and has been made greylist-max-q. Please file a bug if you still "
-                    + "require this API.")
-    public static String defaultLanguageForMcc(int mcc) {
-        MccEntry entry = entryForMcc(mcc);
-        if (entry == null) {
-            Slog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): no country for mcc");
+    @NonNull
+    public static String geoCountryCodeForMccMnc(@NonNull MccMnc mccMnc) {
+        String countryCode = null;
+        if (mccMnc.mnc != null) {
+            countryCode = countryCodeForMccMncNoFallback(mccMnc);
+        }
+        if (TextUtils.isEmpty(countryCode)) {
+            // Try the MCC-only fallback.
+            countryCode = MccTable.countryCodeForMcc(mccMnc.mcc);
+        }
+        return countryCode;
+    }
+
+    @Nullable
+    private static String countryCodeForMccMncNoFallback(MccMnc mccMnc) {
+        synchronized (MccTable.class) {
+            if (sTelephonyNetworkFinder == null) {
+                sTelephonyNetworkFinder = TelephonyLookup.getInstance().getTelephonyNetworkFinder();
+            }
+        }
+        if (sTelephonyNetworkFinder == null) {
+            // This should not happen under normal circumstances, only when the data is missing.
             return null;
         }
-
-        final String country = entry.mIso;
-
-        // Choose English as the default language for India.
-        if ("in".equals(country)) {
-            return "en";
+        TelephonyNetwork network =
+                sTelephonyNetworkFinder.findNetworkByMccMnc(mccMnc.mcc, mccMnc.mnc);
+        if (network == null) {
+            return null;
         }
-
-        // 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);
-        return likelyLanguage;
+        return network.getCountryIsoCode();
     }
 
+
     /**
      * Given a GSM Mobile Country Code, returns
      * the smallest number of digits that M if available.
@@ -178,13 +274,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) {
+        if (TelephonyUtils.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 + "'");
             }
         }
 
@@ -195,11 +291,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();
@@ -211,13 +307,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);
             }
         }
     }
@@ -225,161 +321,13 @@
     /**
      * Maps a given locale to a fallback locale that approximates it. This is a hack.
      */
-    private static final Map<Locale, Locale> FALLBACKS = new HashMap<Locale, Locale>();
+    public static final Map<Locale, Locale> FALLBACKS = new HashMap<Locale, Locale>();
 
     static {
         // If we have English (without a country) explicitly prioritize en_US. http://b/28998094
         FALLBACKS.put(Locale.ENGLISH, Locale.US);
     }
 
-    /**
-     * Finds a suitable locale among {@code candidates} to use as the fallback locale for
-     * {@code target}. This looks through the list of {@link #FALLBACKS}, and follows the chain
-     * until a locale in {@code candidates} is found.
-     * This function assumes that {@code target} is not in {@code candidates}.
-     *
-     * TODO: This should really follow the CLDR chain of parent locales! That might be a bit
-     * of a problem because we don't really have an en-001 locale on android.
-     *
-     * @return The fallback locale or {@code null} if there is no suitable fallback defined in the
-     *         lookup.
-     */
-    private static Locale lookupFallback(Locale target, List<Locale> candidates) {
-        Locale fallback = target;
-        while ((fallback = FALLBACKS.get(fallback)) != null) {
-            if (candidates.contains(fallback)) {
-                return fallback;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Return Locale for the language and country or null if no good match.
-     *
-     * @param context Context to act on.
-     * @param language Two character language code desired
-     * @param country Two character country code desired
-     *
-     * @return Locale or null if no appropriate value
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
-            publicAlternatives = "There is no alternative for {@code MccTable"
-                    + ".getLocaleForLanguageCountry}, but it was included in hidden APIs due to a "
-                    + "static analysis false positive and has been made greylist-max-q. Please "
-                    + "file a bug if you still require this API.")
-    private static Locale getLocaleForLanguageCountry(Context context, String language,
-            String country) {
-        if (language == null) {
-            Slog.d(LOG_TAG, "getLocaleForLanguageCountry: skipping no language");
-            return null; // no match possible
-        }
-        if (country == null) {
-            country = ""; // The Locale constructor throws if passed null.
-        }
-
-        final Locale target = new Locale(language, country);
-        try {
-            String[] localeArray = context.getAssets().getLocales();
-            List<String> locales = new ArrayList<>(Arrays.asList(localeArray));
-
-            // Even in developer mode, you don't want the pseudolocales.
-            locales.remove("ar-XB");
-            locales.remove("en-XA");
-
-            List<Locale> languageMatches = new ArrayList<>();
-            for (String locale : locales) {
-                final Locale l = Locale.forLanguageTag(locale.replace('_', '-'));
-
-                // Only consider locales with both language and country.
-                if (l == null || "und".equals(l.getLanguage()) ||
-                        l.getLanguage().isEmpty() || l.getCountry().isEmpty()) {
-                    continue;
-                }
-                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());
-                        return l;
-                    }
-
-                    // We've only matched the language, not the country.
-                    languageMatches.add(l);
-                }
-            }
-
-            if (languageMatches.isEmpty()) {
-                Slog.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: "
-                        + bestMatch.toLanguageTag());
-                return bestMatch;
-            } else {
-                // Ask {@link LocaleStore} whether this locale is considered "translated".
-                // LocaleStore has a broader definition of translated than just the asset locales
-                // above: a locale is "translated" if it has translation assets, or another locale
-                // with the same language and script has translation assets.
-                // If a locale is "translated", it is selectable in setup wizard, and can therefore
-                // be considerd a valid result for this method.
-                if (!TextUtils.isEmpty(target.getCountry())) {
-                    LocaleStore.fillCache(context);
-                    LocaleInfo targetInfo = LocaleStore.getLocaleInfo(target);
-                    if (targetInfo.isTranslated()) {
-                        Slog.d(LOG_TAG, "getLocaleForLanguageCountry: "
-                                + "target locale is translated: " + target);
-                        return target;
-                    }
-                }
-
-                // Somewhat arbitrarily take the first locale for the language,
-                // 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: "
-                        + language);
-                return languageMatches.get(0);
-            }
-        } catch (Exception e) {
-            Slog.d(LOG_TAG, "getLocaleForLanguageCountry: exception", e);
-        }
-
-        return null;
-    }
-
-    /**
-     * Get Locale based on the MCC of the SIM.
-     *
-     * @param context Context to act on.
-     * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
-     * @param simLanguage (nullable) the language from the SIM records (if present).
-     *
-     * @return locale for the mcc or null if none
-     */
-    public static Locale getLocaleFromMcc(Context context, int mcc, String simLanguage) {
-        boolean hasSimLanguage = !TextUtils.isEmpty(simLanguage);
-        String language = hasSimLanguage ? simLanguage : MccTable.defaultLanguageForMcc(mcc);
-        String country = MccTable.countryCodeForMcc(mcc);
-
-        Slog.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);
-            return getLocaleForLanguageCountry(context, language, country);
-        }
-
-        return locale;
-    }
-
     static {
         sTable = new ArrayList<MccEntry>(240);
 
diff --git a/src/java/com/android/internal/telephony/MmiCode.java b/src/java/com/android/internal/telephony/MmiCode.java
index eb09621..d4b1a0a 100644
--- a/src/java/com/android/internal/telephony/MmiCode.java
+++ b/src/java/com/android/internal/telephony/MmiCode.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.ResultReceiver;
 
 import java.util.regex.Pattern;
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index 1ce360f..7ad0de4 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;
@@ -407,7 +407,7 @@
         if (DBG) log("onSubscriptionGroupChanged");
 
         List<SubscriptionInfo> infoList = mSubController.getSubscriptionsInGroup(
-                groupUuid, mContext.getOpPackageName());
+                groupUuid, mContext.getOpPackageName(), null);
         if (infoList == null || infoList.isEmpty()) return;
 
         // Get a reference subscription to copy settings from.
@@ -470,7 +470,8 @@
         if (!isReadyToReevaluate()) return;
 
         List<SubscriptionInfo> activeSubInfos = mSubController
-                .getActiveSubscriptionInfoList(mContext.getOpPackageName());
+                .getActiveSubscriptionInfoList(mContext.getOpPackageName(),
+                        null);
 
         if (ArrayUtils.isEmpty(activeSubInfos)) {
             mPrimarySubList.clear();
@@ -644,7 +645,8 @@
             if (phone != null && phone.isCdmaSubscriptionAppPresent()) {
                 cdmaPhoneCount++;
                 String simName = mSubController.getActiveSubscriptionInfo(
-                        subId, mContext.getOpPackageName()).getDisplayName().toString();
+                        subId, mContext.getOpPackageName(), null)
+                        .getDisplayName().toString();
                 if (TextUtils.isEmpty(simName)) {
                     // Fall back to carrier name.
                     simName = phone.getCarrierName();
@@ -700,7 +702,8 @@
     private void setUserDataEnabledForGroup(int subId, boolean enable) {
         log("setUserDataEnabledForGroup subId " + subId + " enable " + enable);
         List<SubscriptionInfo> infoList = mSubController.getSubscriptionsInGroup(
-                mSubController.getGroupUuid(subId), mContext.getOpPackageName());
+                mSubController.getGroupUuid(subId), mContext.getOpPackageName(),
+                null);
 
         if (infoList == null) return;
 
@@ -730,7 +733,8 @@
     private void setRoamingDataEnabledForGroup(int subId, boolean enable) {
         SubscriptionController subController = SubscriptionController.getInstance();
         List<SubscriptionInfo> infoList = subController.getSubscriptionsInGroup(
-                mSubController.getGroupUuid(subId), mContext.getOpPackageName());
+                mSubController.getGroupUuid(subId), mContext.getOpPackageName(),
+                null);
 
         if (infoList == null) return;
 
@@ -778,7 +782,7 @@
         if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return;
 
         List<SubscriptionInfo> opptSubList = mSubController.getOpportunisticSubscriptions(
-                mContext.getOpPackageName());
+                mContext.getOpPackageName(), null);
 
         if (ArrayUtils.isEmpty(opptSubList)) return;
 
diff --git a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
index 1b28be4..716e7a2 100644
--- a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
+++ b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.IBinder;
@@ -37,10 +38,11 @@
 import android.telephony.INetworkServiceCallback;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.NetworkService;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 
+import com.android.telephony.Rlog;
+
 import java.util.Hashtable;
 import java.util.Map;
 
@@ -99,8 +101,14 @@
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
-        phone.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                intentFilter, null, null);
+        try {
+            Context contextAsUser = phone.getContext().createPackageContextAsUser(
+                    phone.getContext().getPackageName(), 0, UserHandle.ALL);
+            contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter,
+                    null /* broadcastPermission */, null);
+        } catch (PackageManager.NameNotFoundException e) {
+            loge("Package name not found: " + e.getMessage());
+        }
         PhoneConfigurationManager.registerForMultiSimConfigChange(
                 this, EVENT_BIND_NETWORK_SERVICE, null);
 
diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
index c848358..94ea9d0 100644
--- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
+++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
@@ -19,6 +19,7 @@
 import static android.os.Binder.withCleanCallingIdentity;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN;
+import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN;
 
 import android.content.Context;
@@ -66,10 +67,12 @@
     private static final int EVENT_STOP_NETWORK_SCAN_DONE = 5;
     private static final int CMD_INTERRUPT_NETWORK_SCAN = 6;
     private static final int EVENT_INTERRUPT_NETWORK_SCAN_DONE = 7;
+    private static final int EVENT_MODEM_RESET = 8;
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
+            Log.d(TAG, "Received Event :" + msg.what);
             switch (msg.what) {
                 case CMD_START_NETWORK_SCAN:
                     mScheduler.doStartScan((NetworkScanRequestInfo) msg.obj);
@@ -98,6 +101,14 @@
                 case EVENT_INTERRUPT_NETWORK_SCAN_DONE:
                     mScheduler.interruptScanDone((AsyncResult) msg.obj);
                     break;
+
+                case EVENT_MODEM_RESET:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    mScheduler.deleteScanAndMayNotify(
+                            (NetworkScanRequestInfo) ar.userObj,
+                            NetworkScan.ERROR_MODEM_ERROR,
+                            true);
+                    break;
             }
         }
     };
@@ -123,7 +134,8 @@
         }
         for (RadioAccessSpecifier ras : nsri.mRequest.getSpecifiers()) {
             if (ras.getRadioAccessNetwork() != GERAN && ras.getRadioAccessNetwork() != UTRAN
-                    && ras.getRadioAccessNetwork() != EUTRAN) {
+                    && ras.getRadioAccessNetwork() != EUTRAN
+                    && ras.getRadioAccessNetwork() != NGRAN) {
                 return false;
             }
             if (ras.getBands() != null && ras.getBands().length > NetworkScanRequest.MAX_BANDS) {
@@ -179,7 +191,7 @@
      */
     public static Set<String> getAllowedMccMncsForLocationRestrictedScan(Context context) {
         return withCleanCallingIdentity(() -> SubscriptionController.getInstance()
-            .getAvailableSubscriptionInfoList(context.getOpPackageName()).stream()
+            .getAvailableSubscriptionInfoList(context.getOpPackageName(), null).stream()
             .flatMap(NetworkScanRequestTracker::getAllowableMccMncsFromSubscriptionInfo)
             .collect(Collectors.toSet()));
     }
@@ -551,6 +563,7 @@
                 mLiveRequestInfo = nsri;
                 nsri.mPhone.startNetworkScan(nsri.getRequest(),
                         mHandler.obtainMessage(EVENT_START_NETWORK_SCAN_DONE, nsri));
+                nsri.mPhone.mCi.registerForModemReset(mHandler, EVENT_MODEM_RESET, nsri);
                 return true;
             }
             return false;
@@ -570,6 +583,7 @@
                                 null);
                     }
                 }
+                mLiveRequestInfo.mPhone.mCi.unregisterForModemReset(mHandler);
                 mLiveRequestInfo = null;
                 if (mPendingRequestInfo != null) {
                     startNewScan(mPendingRequestInfo);
diff --git a/src/java/com/android/internal/telephony/NitzData.java b/src/java/com/android/internal/telephony/NitzData.java
index 8ecf742..f508d9e 100644
--- a/src/java/com/android/internal/telephony/NitzData.java
+++ b/src/java/com/android/internal/telephony/NitzData.java
@@ -18,9 +18,8 @@
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 
-import android.telephony.Rlog;
-
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.telephony.Rlog;
 
 import java.util.Calendar;
 import java.util.TimeZone;
diff --git a/src/java/com/android/internal/telephony/NitzStateMachine.java b/src/java/com/android/internal/telephony/NitzStateMachine.java
index ec5aaa6..e1f854c 100644
--- a/src/java/com/android/internal/telephony/NitzStateMachine.java
+++ b/src/java/com/android/internal/telephony/NitzStateMachine.java
@@ -21,8 +21,8 @@
 import android.content.Context;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.TimestampedValue;
 import android.provider.Settings;
-import android.util.TimestampedValue;
 
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -51,7 +51,8 @@
     void handleNetworkAvailable();
 
     /**
-     * Informs the {@link NitzStateMachine} that the network has become unavailable.
+     * Informs the {@link NitzStateMachine} that the network has become unavailable. Any network
+     * state, i.e. NITZ, should be cleared.
      */
     void handleNetworkUnavailable();
 
diff --git a/src/java/com/android/internal/telephony/NitzStateMachineImpl.java b/src/java/com/android/internal/telephony/NitzStateMachineImpl.java
index 23152ac..7a4a3b8 100644
--- a/src/java/com/android/internal/telephony/NitzStateMachineImpl.java
+++ b/src/java/com/android/internal/telephony/NitzStateMachineImpl.java
@@ -16,19 +16,19 @@
 
 package com.android.internal.telephony;
 
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
 import android.content.Context;
 import android.os.PowerManager;
-import android.telephony.Rlog;
+import android.os.TimestampedValue;
 import android.text.TextUtils;
+import android.timezone.CountryTimeZones.OffsetResult;
 import android.util.LocalLog;
-import android.util.TimestampedValue;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
-import com.android.internal.telephony.TimeZoneLookupHelper.OffsetResult;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -89,8 +89,8 @@
     private boolean mNitzTimeZoneDetectionSuccessful = false;
 
     // Miscellaneous dependencies and helpers not related to detection state.
-    private final LocalLog mTimeLog = new LocalLog(30);
-    private final LocalLog mTimeZoneLog = new LocalLog(30);
+    private final LocalLog mTimeLog = new LocalLog(30, false /* useLocalTimestamps */);
+    private final LocalLog mTimeZoneLog = new LocalLog(30, false /* useLocalTimestamps */);
     private final Phone mPhone;
     private final DeviceState mDeviceState;
     private final TimeServiceHelper mTimeServiceHelper;
@@ -253,7 +253,7 @@
             // Set state as needed.
             if (zoneId != null) {
                 if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) {
-                    setAndBroadcastNetworkSetTimeZone(zoneId, logMsg);
+                    setTimeZone(zoneId, logMsg);
                 } else {
                     if (DBG) {
                         logMsg += " [Not setting device time zone]";
@@ -267,6 +267,8 @@
                     logMsg += " [Not setting device time zone (zoneId == null)]";
                     Rlog.d(LOG_TAG, logMsg);
                 }
+                mSavedTimeZoneId = null;
+                mNitzTimeZoneDetectionSuccessful = false;
             }
         } catch (RuntimeException ex) {
             Rlog.e(LOG_TAG, "updateTimeZoneFromCountryAndNitz: Processing NITZ data"
@@ -319,19 +321,27 @@
         mSavedNitzTime = null;
         mTimeLog.log("handleNetworkUnavailable: NITZ state cleared.");
 
+        TimestampedValue<NitzData> oldNitzSignal = mLatestNitzSignal;
         mLatestNitzSignal = null;
         mNitzTimeZoneDetectionSuccessful = false;
         mSavedTimeZoneId = null;
         mTimeZoneLog.log("handleNetworkUnavailable: NITZ state cleared.");
 
-        // mSavedTimeZoneId has been cleared but it might be sufficient to detect the time zone
-        // using only the country information that is left.
-        String isoCountryCode = mCountryIsoCode;
-        if (isoCountryCode != null) {
-            if (!TextUtils.isEmpty(isoCountryCode)) {
-                updateTimeZoneFromNetworkCountryCode(isoCountryCode);
-            }
+        // Avoid doing work unnecessarily: if the mLatestNitzSignal was already null we have nothing
+        // to do as it will have been done last time the mLatestNitzSignal was cleared.
+        if (oldNitzSignal == null) {
+            return;
         }
+
+        // mSavedTimeZoneId has been cleared but using only the country information that is left
+        // might be sufficient to detect the time zone.
+        String isoCountryCode = mCountryIsoCode;
+        // We don't need to do country-based time zone detection if the isoCountryCode is null
+        // (unknown) or empty (test cell). TextUtils.isEmpty() does both checks in one.
+        if (!TextUtils.isEmpty(isoCountryCode)) {
+            updateTimeZoneFromNetworkCountryCode(isoCountryCode);
+        }
+        sendEmptyTimeSuggestion("handleNetworkUnavailable");
     }
 
     @Override
@@ -348,7 +358,7 @@
     @Override
     public void handleNitzReceived(TimestampedValue<NitzData> nitzSignal) {
         // Always store the latest NITZ signal received.
-        mLatestNitzSignal = nitzSignal;
+        mLatestNitzSignal = Objects.requireNonNull(nitzSignal);
 
         updateTimeZoneFromCountryAndNitz();
         updateTimeFromNitz();
@@ -376,14 +386,30 @@
         mTimeLog.log("handleAirplaneModeChanged(" + on + "): Time state cleared.");
 
         mCountryIsoCode = null;
+
+        TimestampedValue<NitzData> oldNitzSignal = mLatestNitzSignal;
         mLatestNitzSignal = null;
         mNitzTimeZoneDetectionSuccessful = false;
         mSavedTimeZoneId = null;
+
+        if (oldNitzSignal == null) {
+            // No work to do - terminate early.
+            return;
+        }
+
         mTimeZoneLog.log("handleAirplaneModeChanged(" + on + "): Time zone state cleared.");
+        sendEmptyTimeSuggestion("handleAirplaneModeChanged(" + on + ")");
+    }
+
+    private void sendEmptyTimeSuggestion(String reason) {
+        TelephonyTimeSuggestion timeSuggestion =
+                new TelephonyTimeSuggestion.Builder(mPhone.getPhoneId()).build();
+        timeSuggestion.addDebugInfo("Empty suggestion, reason=" + reason);
+        mTimeServiceHelper.suggestDeviceTime(timeSuggestion);
     }
 
     private void updateTimeFromNitz() {
-        TimestampedValue<NitzData> nitzSignal = mLatestNitzSignal;
+        TimestampedValue<NitzData> nitzSignal = Objects.requireNonNull(mLatestNitzSignal);
         try {
             boolean ignoreNitz = mDeviceState.getIgnoreNitz();
             if (ignoreNitz) {
@@ -459,10 +485,12 @@
                 Rlog.d(LOG_TAG, logMsg);
             }
             mTimeLog.log(logMsg);
-            PhoneTimeSuggestion phoneTimeSuggestion =
-                    new PhoneTimeSuggestion(mPhone.getPhoneId(), newNitzTime);
-            phoneTimeSuggestion.addDebugInfo(logMsg);
-            mTimeServiceHelper.suggestDeviceTime(phoneTimeSuggestion);
+            TelephonyTimeSuggestion timeSuggestion =
+                    new TelephonyTimeSuggestion.Builder(mPhone.getPhoneId())
+                            .setUtcTime(newNitzTime)
+                            .addDebugInfo(logMsg)
+                            .build();
+            mTimeServiceHelper.suggestDeviceTime(timeSuggestion);
 
             TelephonyMetrics.getInstance().writeNITZEvent(
                     mPhone.getPhoneId(), newNitzTime.getValue());
@@ -476,7 +504,7 @@
         }
     }
 
-    private void setAndBroadcastNetworkSetTimeZone(String zoneId, String logMessage) {
+    private void setTimeZone(String zoneId, String logMessage) {
         logMessage += " [Setting device time zone to zoneId=" + zoneId + "]";
         if (DBG) {
             Rlog.d(LOG_TAG, logMessage);
@@ -503,7 +531,7 @@
         String logMsg = "handleAutoTimeZoneEnabled: "
                 + " mSavedTimeZoneId=" + mSavedTimeZoneId;
         if (mSavedTimeZoneId != null) {
-            setAndBroadcastNetworkSetTimeZone(mSavedTimeZoneId, logMsg);
+            setTimeZone(mSavedTimeZoneId, logMsg);
         } else {
             if (DBG) {
                 logMsg += " [Not setting device time zone]";
@@ -562,7 +590,7 @@
 
             String zoneId = lookupResult.zoneId;
             if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) {
-                setAndBroadcastNetworkSetTimeZone(zoneId, logMsg);
+                setTimeZone(zoneId, logMsg);
             } else {
                 if (DBG) {
                     logMsg += " [Not setting device time zone]";
@@ -576,6 +604,7 @@
                         + " iso=" + iso
                         + " lookupResult=" + lookupResult);
             }
+            mSavedTimeZoneId = null;
         }
     }
 
@@ -588,4 +617,9 @@
     public NitzData getCachedNitzData() {
         return mLatestNitzSignal != null ? mLatestNitzSignal.getValue() : null;
     }
+
+    // VisibleForTesting
+    public String getSavedTimeZoneId() {
+        return mSavedTimeZoneId;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index fd22e77..8a0e497 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -16,20 +16,18 @@
 
 package com.android.internal.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.BroadcastOptions;
-import android.content.BroadcastReceiver;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
 import android.net.NetworkStats;
 import android.net.Uri;
 import android.os.AsyncResult;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -40,20 +38,21 @@
 import android.os.SystemProperties;
 import android.os.WorkSource;
 import android.preference.PreferenceManager;
+import android.sysprop.TelephonyProperties;
 import android.telecom.VideoProfile;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.DataFailureCause;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CarrierRestrictionRules;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
-import android.telephony.CellLocation;
 import android.telephony.ClientRequestStats;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.PhysicalChannelConfig;
+import android.telephony.PreciseDataConnectionState;
 import android.telephony.RadioAccessFamily;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
@@ -70,6 +69,7 @@
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons;
 import com.android.internal.telephony.dataconnection.DataEnabledSettings;
 import com.android.internal.telephony.dataconnection.DcTracker;
@@ -85,6 +85,8 @@
 import com.android.internal.telephony.uicc.UiccCardApplication;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UsimServiceTable;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -116,33 +118,6 @@
 
     protected final int USSD_MAX_QUEUE = 10;
 
-    private BroadcastReceiver mImsIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Rlog.d(LOG_TAG, "mImsIntentReceiver: action " + intent.getAction());
-            if (intent.hasExtra(ImsManager.EXTRA_PHONE_ID)) {
-                int extraPhoneId = intent.getIntExtra(ImsManager.EXTRA_PHONE_ID,
-                        SubscriptionManager.INVALID_PHONE_INDEX);
-                Rlog.d(LOG_TAG, "mImsIntentReceiver: extraPhoneId = " + extraPhoneId);
-                if (extraPhoneId == SubscriptionManager.INVALID_PHONE_INDEX ||
-                        extraPhoneId != getPhoneId()) {
-                    return;
-                }
-            }
-
-            synchronized (Phone.lockForRadioTechnologyChange) {
-                if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_UP)) {
-                    mImsServiceReady = true;
-                    updateImsPhone();
-                    ImsManager.getInstance(mContext, mPhoneId).updateImsServiceConfig(false);
-                } else if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_DOWN)) {
-                    mImsServiceReady = false;
-                    updateImsPhone();
-                }
-            }
-        }
-    };
-
     // Key used to read and write the saved network selection numeric value
     public static final String NETWORK_SELECTION_KEY = "network_selection_key";
     // Key used to read and write the saved network selection operator name
@@ -198,7 +173,8 @@
     // other
     protected static final int EVENT_SET_NETWORK_AUTOMATIC          = 28;
     protected static final int EVENT_ICC_RECORD_EVENTS              = 29;
-    private static final int EVENT_ICC_CHANGED                      = 30;
+    @VisibleForTesting
+    protected static final int EVENT_ICC_CHANGED                    = 30;
     // Single Radio Voice Call Continuity
     private static final int EVENT_SRVCC_STATE_CHANGED              = 31;
     private static final int EVENT_INITIATE_SILENT_REDIAL           = 32;
@@ -224,9 +200,13 @@
     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_REAPPLY_UICC_APPS_ENABLEMENT_DONE = 55;
+    protected static final int EVENT_REGISTRATION_FAILED = 56;
 
-    protected static final int EVENT_LAST = EVENT_ALL_DATA_DISCONNECTED;
+    protected static final int EVENT_LAST = EVENT_REGISTRATION_FAILED;
 
     // For shared prefs.
     private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
@@ -323,7 +303,6 @@
     @UnsupportedAppUsage
     protected int mPhoneId;
 
-    private boolean mImsServiceReady = false;
     @UnsupportedAppUsage
     protected Phone mImsPhone = null;
 
@@ -342,8 +321,20 @@
      * TODO: Replace this with a proper exception; {@link CallStateException} doesn't make sense.
      */
     public static final String CS_FALLBACK = "cs_fallback";
-    public static final String EXTRA_KEY_ALERT_TITLE = "alertTitle";
-    public static final String EXTRA_KEY_ALERT_MESSAGE = "alertMessage";
+    /**
+     * @deprecated Use {@link android.telephony.ims.ImsManager#EXTRA_WFC_REGISTRATION_FAILURE_TITLE}
+     * instead.
+     */
+    @Deprecated
+    public static final String EXTRA_KEY_ALERT_TITLE =
+            android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_TITLE;
+    /**
+     * @deprecated Use
+     * {@link android.telephony.ims.ImsManager#EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE} instead.
+     */
+    @Deprecated
+    public static final String EXTRA_KEY_ALERT_MESSAGE =
+            android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE;
     public static final String EXTRA_KEY_ALERT_SHOW = "alertShow";
     public static final String EXTRA_KEY_NOTIFICATION_MESSAGE = "notificationMessage";
 
@@ -382,6 +373,10 @@
 
     private final RegistrantList mRedialRegistrants = new RegistrantList();
 
+    private final RegistrantList mPhysicalChannelConfigRegistrants = new RegistrantList();
+
+    private final RegistrantList mOtaspRegistrants = new RegistrantList();
+
     protected Registrant mPostDialHandler;
 
     protected final LocalLog mLocalLog;
@@ -452,27 +447,6 @@
     }
 
     /**
-     * Set a system property for the current phone, unless we're in unit test mode
-     */
-    // CAF_MSIM TODO this need to be replated with TelephonyManager API ?
-    public void setSystemProperty(String property, String value) {
-        if (getUnitTestMode()) {
-            return;
-        }
-        TelephonyManager.setTelephonyProperty(mPhoneId, property, value);
-    }
-
-    /**
-     * Set a system property for all phones, unless we're in unit test mode
-     */
-    public void setGlobalSystemProperty(String property, String value) {
-        if (getUnitTestMode()) {
-            return;
-        }
-        TelephonyManager.setTelephonyProperty(property, value);
-    }
-
-    /**
      * Set a system property, unless we're in unit test mode
      */
     // CAF_MSIM TODO this need to be replated with TelephonyManager API ?
@@ -526,7 +500,7 @@
                 .makeAppSmsManager(context);
         mLocalLog = new LocalLog(64);
 
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             mTelephonyTester = new TelephonyTester(this);
         }
 
@@ -542,8 +516,8 @@
         * This will be false on "data only" devices which can't make voice
         * calls and don't support any in-call UI.
         */
-        mIsVoiceCapable = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
+        mIsVoiceCapable = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE))
+                .isVoiceCapable();
 
         /**
          *  Some RIL's don't always send RIL_UNSOL_CALL_RING so it needs
@@ -555,12 +529,11 @@
          * the RIL_UNSOL_CALL_RING so the default if there is no property is
          * true.
          */
-        mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
-                TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
+        mDoesRilSendMultipleCallRing = TelephonyProperties.ril_sends_multiple_call_ring()
+                .orElse(true);
         Rlog.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
 
-        mCallRingDelay = SystemProperties.getInt(
-                TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
+        mCallRingDelay = TelephonyProperties.call_ring_delay().orElse(3000);
         Rlog.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
 
         if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
@@ -586,34 +559,20 @@
     }
 
     /**
-     * Start listening for IMS service UP/DOWN events. If using the new ImsResolver APIs, we should
-     * always be setting up ImsPhones.
+     * Start setup of ImsPhone, which will start trying to connect to the ImsResolver. Will not be
+     * called if this device does not support FEATURE_IMS_TELEPHONY.
      */
-    public void startMonitoringImsService() {
+    public void createImsPhone() {
         if (getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
             return;
         }
 
         synchronized(Phone.lockForRadioTechnologyChange) {
-            IntentFilter filter = new IntentFilter();
-            ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
-            // Don't listen to deprecated intents using the new dynamic binding.
-            if (imsManager != null && !imsManager.isDynamicBinding()) {
-                filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
-                filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
-                mContext.registerReceiver(mImsIntentReceiver, filter);
-            }
-
-            // Monitor IMS service - but first poll to see if already up (could miss
-            // intent). Also, when using new ImsResolver APIs, the service will be available soon,
-            // so start trying to bind.
-            if (imsManager != null) {
-                // If it is dynamic binding, kick off ImsPhone creation now instead of waiting for
-                // the service to be available.
-                if (imsManager.isDynamicBinding() || imsManager.isServiceAvailable()) {
-                    mImsServiceReady = true;
-                    updateImsPhone();
-                }
+            if (mImsPhone == null) {
+                mImsPhone = PhoneFactory.makeImsPhone(mNotifier, this);
+                CallManager.getInstance().registerPhone(mImsPhone);
+                mImsPhone.registerForSilentRedial(
+                        this, EVENT_INITIATE_SILENT_REDIAL, null);
             }
         }
     }
@@ -1425,7 +1384,7 @@
         nsm.operatorAlphaShort = network.getOperatorAlphaShort();
 
         Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
-        mCi.setNetworkSelectionModeManual(network.getOperatorNumeric(), msg);
+        mCi.setNetworkSelectionModeManual(network.getOperatorNumeric(), network.getRan(), msg);
 
         if (persistSelection) {
             updateSavedNetworkOperator(nsm);
@@ -1918,17 +1877,16 @@
     /**
      * @return the current cell location if known
      */
-    @UnsupportedAppUsage
-    public CellLocation getCellLocation() {
-        return getServiceStateTracker().getCellLocation();
+    public CellIdentity getCellIdentity() {
+        return getServiceStateTracker().getCellIdentity();
     }
 
     /**
      * @param workSource calling WorkSource
      * @param rspMsg the response message containing the cell location
      */
-    public void getCellLocation(WorkSource workSource, Message rspMsg) {
-        getServiceStateTracker().requestCellLocation(workSource, rspMsg);
+    public void getCellIdentity(WorkSource workSource, Message rspMsg) {
+        getServiceStateTracker().requestCellIdentity(workSource, rspMsg);
     }
 
     /**
@@ -2010,10 +1968,11 @@
 
     public void setVoiceCallForwardingFlag(int line, boolean enable, String number) {
         setCallForwardingIndicatorInSharedPref(enable);
-        IccRecords r = mIccRecords.get();
+        IccRecords r = getIccRecords();
         if (r != null) {
             r.setVoiceCallForwardingFlag(line, enable, number);
         }
+        notifyCallForwardingIndicator();
     }
 
     /**
@@ -2027,7 +1986,10 @@
     public void setVoiceCallForwardingFlag(IccRecords r, int line, boolean enable,
                                               String number) {
         setCallForwardingIndicatorInSharedPref(enable);
-        r.setVoiceCallForwardingFlag(line, enable, number);
+        if (r != null) {
+            r.setVoiceCallForwardingFlag(line, enable, number);
+        }
+        notifyCallForwardingIndicator();
     }
 
     /**
@@ -2041,7 +2003,7 @@
             Rlog.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA");
             return false;
         }
-        IccRecords r = mIccRecords.get();
+        IccRecords r = getIccRecords();
         int callForwardingIndicator = IccRecords.CALL_FORWARDING_STATUS_UNKNOWN;
         if (r != null) {
             callForwardingIndicator = r.getVoiceCallForwardingFlag();
@@ -2362,6 +2324,15 @@
         mCi.nvResetConfig(3 /* factory NV reset */, response);
     }
 
+    /**
+     * Perform modem configuration erase. Used for network reset
+     *
+     * @param response Callback message.
+     */
+    public void eraseModemConfig(Message response) {
+        mCi.nvResetConfig(2 /* erase NV */, response);
+    }
+
     public void notifyDataActivity() {
         mNotifier.notifyDataActivity(this);
     }
@@ -2375,23 +2346,22 @@
         mNotifier.notifyMessageWaitingChanged(this);
     }
 
+    /** Send notification with an updated PreciseDataConnectionState to a single data connection */
     public void notifyDataConnection(String apnType) {
-        mNotifier.notifyDataConnection(this, apnType, getDataConnectionState(apnType));
+        mNotifier.notifyDataConnection(this, apnType, getPreciseDataConnectionState(apnType));
     }
 
-    public void notifyDataConnection() {
+    /** Send notification with an updated PreciseDataConnectionState to all data connections */
+    public void notifyAllActiveDataConnections() {
         String types[] = getActiveApnTypes();
-        if (types != null) {
-            for (String apnType : types) {
-                mNotifier.notifyDataConnection(this, apnType,
-                        getDataConnectionState(apnType));
-            }
+        for (String apnType : types) {
+            mNotifier.notifyDataConnection(this, apnType, getPreciseDataConnectionState(apnType));
         }
     }
 
     @UnsupportedAppUsage
     public void notifyOtaspChanged(int otaspMode) {
-        mNotifier.notifyOtaspChanged(this, otaspMode);
+        mOtaspRegistrants.notifyRegistrants(new AsyncResult(null, otaspMode, null));
     }
 
     public void notifyVoiceActivationStateChanged(int state) {
@@ -2414,6 +2384,11 @@
         return PhoneConstants.DataState.DISCONNECTED;
     }
 
+    /** Default implementation to get the PreciseDataConnectionState */
+    public @Nullable PreciseDataConnectionState getPreciseDataConnectionState(String apnType) {
+        return null;
+    }
+
     public void notifyCellInfo(List<CellInfo> cellInfo) {
         AsyncResult ar = new AsyncResult(null, cellInfo, null);
         mCellInfoRegistrants.notifyRegistrants(ar);
@@ -2421,9 +2396,34 @@
         mNotifier.notifyCellInfo(this, cellInfo);
     }
 
+    /**
+     * Registration point for PhysicalChannelConfig change.
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj.userObj
+     */
+    public void registerForPhysicalChannelConfig(Handler h, int what, Object obj) {
+        checkCorrectThread(h);
+        Registrant registrant = new Registrant(h, what, obj);
+        mPhysicalChannelConfigRegistrants.add(registrant);
+        // notify first
+        List<PhysicalChannelConfig> physicalChannelConfigs = getPhysicalChannelConfigList();
+        if (physicalChannelConfigs != null) {
+            registrant.notifyRegistrant(new AsyncResult(null, physicalChannelConfigs, null));
+        }
+    }
+
+    public void unregisterForPhysicalChannelConfig(Handler h) {
+        mPhysicalChannelConfigRegistrants.remove(h);
+    }
+
     /** Notify {@link PhysicalChannelConfig} changes. */
     public void notifyPhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
-        mNotifier.notifyPhysicalChannelConfiguration(this, configs);
+        mPhysicalChannelConfigRegistrants.notifyRegistrants(new AsyncResult(null, configs, null));
+    }
+
+    public List<PhysicalChannelConfig> getPhysicalChannelConfigList() {
+        return null;
     }
 
     /**
@@ -2458,7 +2458,7 @@
     // This property is used to handle phone process crashes, and is the same for CDMA and IMS
     // phones
     protected static boolean getInEcmMode() {
-        return SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false);
+        return TelephonyProperties.in_ecm_mode().orElse(false);
     }
 
     /**
@@ -2470,8 +2470,14 @@
         return mIsPhoneInEcmState;
     }
 
+    public boolean isInImsEcm() {
+        return false;
+    }
+
     public void setIsInEcm(boolean isInEcm) {
-        setGlobalSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, String.valueOf(isInEcm));
+        if (!getUnitTestMode()) {
+            TelephonyProperties.in_ecm_mode(isInEcm);
+        }
         mIsPhoneInEcmState = isInEcm;
     }
 
@@ -2620,7 +2626,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
@@ -2628,7 +2635,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());
         }
     }
@@ -2799,6 +2807,42 @@
     }
 
     /**
+     * Register for notifications when OTA Service Provisioning mode has changed.
+     *
+     * <p>The mode is integer. {@link TelephonyManager#OTASP_UNKNOWN}
+     * means the value is currently unknown and the system should wait until
+     * {@link TelephonyManager#OTASP_NEEDED} or {@link TelephonyManager#OTASP_NOT_NEEDED} is
+     * received before making the decision to perform OTASP or not.
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForOtaspChange(Handler h, int what, Object obj) {
+        checkCorrectThread(h);
+        mOtaspRegistrants.addUnique(h, what, obj);
+        // notify first
+        new Registrant(h, what, obj).notifyRegistrant(new AsyncResult(null, getOtasp(), null));
+    }
+
+    /**
+     * Unegister for notifications when OTA Service Provisioning mode has changed.
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForOtaspChange(Handler h) {
+        mOtaspRegistrants.remove(h);
+    }
+
+    /**
+     * Returns the current OTA Service Provisioning mode.
+     *
+     * @see registerForOtaspChange
+     */
+    public int getOtasp() {
+        return TelephonyManager.OTASP_UNKNOWN;
+    }
+
+    /**
      * Register for notifications when CDMA call waiting comes
      *
      * @param h Handler that receives the notification message.
@@ -3045,26 +3089,26 @@
 
     /**
      * Returns an array of string identifiers for the APN types serviced by the
-     * currently active.
+     * currently active subscription.
      *
      * @return The string array of APN types. Return null if no active APN types.
      */
     @UnsupportedAppUsage
-    @Nullable
+    @NonNull
     public String[] getActiveApnTypes() {
-        if (mTransportManager != null) {
-            List<String> typesList = new ArrayList<>();
-            for (int transportType : mTransportManager.getAvailableTransports()) {
-                if (getDcTracker(transportType) != null) {
-                    typesList.addAll(Arrays.asList(
-                            getDcTracker(transportType).getActiveApnTypes()));
-                }
-            }
-
-            return typesList.toArray(new String[typesList.size()]);
+        if (mTransportManager == null || mDcTrackers == null)  {
+            Rlog.e(LOG_TAG, "Invalid state for Transport/DcTrackers");
+            return new String[0];
         }
 
-        return null;
+        Set<String> activeApnTypes = new HashSet<String>();
+        for (int transportType : mTransportManager.getAvailableTransports()) {
+            DcTracker dct = getDcTracker(transportType);
+            if (dct == null) continue; // TODO: should this ever happen?
+            activeApnTypes.addAll(Arrays.asList(dct.getActiveApnTypes()));
+        }
+
+        return activeApnTypes.toArray(new String[activeApnTypes.size()]);
     }
 
     /**
@@ -3240,6 +3284,17 @@
     }
 
     /**
+     * Enable or disable always reporting signal strength changes from radio.
+     *
+     * @param isEnable {@code true} for enabling; {@code false} for disabling.
+     */
+    public void setAlwaysReportSignalStrength(boolean isEnable) {
+        if (mDeviceStateMonitor != null) {
+            mDeviceStateMonitor.setAlwaysReportSignalStrength(isEnable);
+        }
+    }
+
+    /**
      * TODO: Adding a function for each property is not good.
      * A fucntion of type getPhoneProp(propType) where propType is an
      * enum of GSM+CDMA+LTE props would be a better approach.
@@ -3294,13 +3349,10 @@
     public void notifyCallForwardingIndicator() {
     }
 
-    public void notifyDataConnectionFailed(String apnType) {
-        mNotifier.notifyDataConnectionFailed(this, apnType);
-    }
-
-    public void notifyPreciseDataConnectionFailed(String apnType, String apn,
-                                                  @DataFailureCause int failCause) {
-        mNotifier.notifyPreciseDataConnectionFailed(this, apnType, apn, failCause);
+    /** Send a notification that a particular data connection has failed with specified cause. */
+    public void notifyDataConnectionFailed(
+            String apnType, String apn, @DataFailureCause int failCause) {
+        mNotifier.notifyDataConnectionFailed(this, apnType, apn, failCause);
     }
 
     /**
@@ -3421,6 +3473,10 @@
         return TelephonyManager.UNKNOWN_CARRIER_ID_LIST_VERSION;
     }
 
+    public int getEmergencyNumberDbVersion() {
+        return TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION;
+    }
+
     public void resolveSubscriptionCarrierId(String simState) {
     }
 
@@ -3448,28 +3504,6 @@
     public void dispose() {
     }
 
-    private void updateImsPhone() {
-        Rlog.d(LOG_TAG, "updateImsPhone"
-                + " mImsServiceReady=" + mImsServiceReady);
-
-        if (mImsServiceReady && (mImsPhone == null)) {
-            mImsPhone = PhoneFactory.makeImsPhone(mNotifier, this);
-            CallManager.getInstance().registerPhone(mImsPhone);
-            mImsPhone.registerForSilentRedial(
-                    this, EVENT_INITIATE_SILENT_REDIAL, null);
-        } else if (!mImsServiceReady && (mImsPhone != null)) {
-            CallManager.getInstance().unregisterPhone(mImsPhone);
-            mImsPhone.unregisterForSilentRedial(this);
-
-            mImsPhone.dispose();
-            // Potential GC issue if someone keeps a reference to ImsPhone.
-            // However: this change will make sure that such a reference does
-            // not access functions through NULL pointer.
-            //mImsPhone.removeReferences();
-            mImsPhone = null;
-        }
-    }
-
     /**
      * Dials a number.
      *
@@ -3900,7 +3934,8 @@
     }
 
     /** Sets the SignalStrength reporting criteria. */
-    public void setSignalStrengthReportingCriteria(int[] thresholds, int ran) {
+    public void setSignalStrengthReportingCriteria(
+            int signalStrengthMeasure, int[] thresholds, int ran, boolean isEnabled) {
         // no-op default implementation
     }
 
@@ -4101,7 +4136,7 @@
                 ServiceState ss = phone.getServiceStateTracker().getServiceState();
                 // One of the phone is in service, hence the device is not emergency call only.
                 if (ss.getState() == ServiceState.STATE_IN_SERVICE
-                        || ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
+                        || ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) {
                     return false;
                 }
                 isEmergencyCallOnly |= ss.isEmergencyOnly();
@@ -4126,6 +4161,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/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index df73ef8..4304199 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -26,14 +26,15 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RegistrantList;
-import android.os.SystemProperties;
 import android.os.storage.StorageManager;
+import android.sysprop.TelephonyProperties;
 import android.telephony.PhoneCapability;
-import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.telephony.Rlog;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -130,19 +131,6 @@
     }
 
     /**
-     * Whether the phoneId has a corresponding active slot / logical modem. If a DSDS capable
-     * device is in single SIM mode, phoneId=1 is valid but not active.
-     *
-     * TODO: b/139642279 combine with SubscriptionManager#isValidPhoneId when phone objects
-     * are dynamically allocated instead of always based on getMaxPhoneCount.
-     * @hide
-     */
-    public static boolean isPhoneActive(int phoneId) {
-        // Currently it simply depends on getPhoneCount. In future it can be generalized.
-        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
-    }
-
-    /**
      * Handler class to handle callbacks
      */
     private final class ConfigManagerHandler extends Handler {
@@ -318,7 +306,7 @@
     }
 
     public int getNumberOfModemsWithSimultaneousDataConnections() {
-        return mStaticCapability.maxActiveData;
+        return mStaticCapability.getMaxActivePsVoice();
     }
 
     private void notifyCapabilityChanged() {
@@ -333,7 +321,7 @@
      */
     public void switchMultiSimConfig(int numOfSims) {
         log("switchMultiSimConfig: with numOfSims = " + numOfSims);
-        if (getStaticPhoneCapability().logicalModemList.size() < numOfSims) {
+        if (getStaticPhoneCapability().getLogicalModemUuids().size() < numOfSims) {
             log("switchMultiSimConfig: Phone is not capable of enabling "
                     + numOfSims + " sims, exiting!");
             return;
@@ -366,11 +354,12 @@
             pm.reboot("Multi-SIM config changed.");
         } else {
             log("onMultiSimConfigChanged: Rebooting is not required.");
+            mMi.notifyPhoneFactoryOnMultiSimConfigChanged(mContext, numOfActiveModems);
             broadcastMultiSimConfigChange(numOfActiveModems);
             // Register to RIL service if needed.
             for (int i = 0; i < mPhones.length; i++) {
                 Phone phone = mPhones[i];
-                phone.mCi.onSlotActiveStatusChange(isPhoneActive(i));
+                phone.mCi.onSlotActiveStatusChange(SubscriptionManager.isValidPhoneId(i));
             }
         }
     }
@@ -426,14 +415,19 @@
      */
     @VisibleForTesting
     public static class MockableInterface {
+        /**
+         * Wrapper function to decide whether reboot is required for modem config change.
+         */
         @VisibleForTesting
         public boolean isRebootRequiredForModemConfigChange() {
-            String rebootRequired = SystemProperties.get(
-                    TelephonyProperties.PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE);
+            boolean rebootRequired = TelephonyProperties.reboot_on_modem_change().orElse(false);
             log("isRebootRequiredForModemConfigChange: isRebootRequired = " + rebootRequired);
-            return !rebootRequired.equals("false");
+            return rebootRequired;
         }
 
+        /**
+         * Wrapper function to call setMultiSimProperties.
+         */
         @VisibleForTesting
         public void setMultiSimProperties(int numOfActiveModems) {
             String multiSimConfig;
@@ -449,7 +443,16 @@
             }
 
             log("setMultiSimProperties to " + multiSimConfig);
-            SystemProperties.set(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG, multiSimConfig);
+            TelephonyProperties.multi_sim_config(multiSimConfig);
+        }
+
+        /**
+         * Wrapper function to call PhoneFactory.onMultiSimConfigChanged.
+         */
+        @VisibleForTesting
+        public void notifyPhoneFactoryOnMultiSimConfigChanged(
+                Context context, int numOfActiveModems) {
+            PhoneFactory.onMultiSimConfigChanged(context, numOfActiveModems);
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index b92c68b..9b181d3 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -16,30 +16,32 @@
 
 package com.android.internal.telephony;
 
+import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA;
+import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA_LTE;
+
+import static java.util.Arrays.copyOf;
+
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.net.LocalServerSocket;
+import android.os.HandlerThread;
 import android.os.Looper;
-import android.os.ServiceManager;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.telephony.AnomalyReporter;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.LocalLog;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.dataconnection.TelephonyNetworkFactory;
 import com.android.internal.telephony.euicc.EuiccCardController;
 import com.android.internal.telephony.euicc.EuiccController;
-import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneFactory;
 import com.android.internal.telephony.sip.SipPhone;
@@ -47,6 +49,7 @@
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -87,9 +90,7 @@
     static private Context sContext;
     static private PhoneConfigurationManager sPhoneConfigurationManager;
     static private PhoneSwitcher sPhoneSwitcher;
-    static private SubscriptionMonitor sSubscriptionMonitor;
     static private TelephonyNetworkFactory[] sTelephonyNetworkFactories;
-    static private ImsResolver sImsResolver;
     static private NotificationChannelController sNotificationChannelController;
     static private CellularNetworkValidator sCellularNetworkValidator;
 
@@ -146,7 +147,7 @@
                 /* In case of multi SIM mode two instances of Phone, RIL are created,
                    where as in single SIM mode only instance. isMultiSimEnabled() function checks
                    whether it is single SIM or multi SIM mode */
-                int numPhones = TelephonyManager.getDefault().getSupportedModemCount();
+                int numPhones = TelephonyManager.getDefault().getActiveModemCount();
 
                 int[] networkModes = new int[numPhones];
                 sPhones = new Phone[numPhones];
@@ -165,7 +166,7 @@
 
                 // Instantiate UiccController so that all other classes can just
                 // call getInstance()
-                sUiccController = UiccController.make(context, sCommandsInterfaces);
+                sUiccController = UiccController.make(context);
 
                 Rlog.i(LOG_TAG, "Creating SubscriptionController");
                 SubscriptionController sc = SubscriptionController.init(context);
@@ -178,28 +179,13 @@
                 }
 
                 for (int i = 0; i < numPhones; i++) {
-                    Phone phone = null;
-                    int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
-                    if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
-                        phone = new GsmCdmaPhone(context,
-                                sCommandsInterfaces[i], sPhoneNotifier, i,
-                                PhoneConstants.PHONE_TYPE_GSM,
-                                TelephonyComponentFactory.getInstance());
-                    } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
-                        phone = new GsmCdmaPhone(context,
-                                sCommandsInterfaces[i], sPhoneNotifier, i,
-                                PhoneConstants.PHONE_TYPE_CDMA_LTE,
-                                TelephonyComponentFactory.getInstance());
-                    }
-                    Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
-
-                    sPhones[i] = phone;
+                    sPhones[i] = createPhone(context, i);
                 }
 
                 // Set the default phone in base class.
                 // FIXME: This is a first best guess at what the defaults will be. It
                 // FIXME: needs to be done in a more controlled manner in the future.
-                sPhone = sPhones[0];
+                if (numPhones > 0) sPhone = sPhones[0];
 
                 // Ensure that we have a default SMS app. Requesting the app with
                 // updateIfNeeded set to true is enough to configure a default SMS app.
@@ -217,41 +203,24 @@
                 sMadeDefaults = true;
 
                 Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
+                HandlerThread pfhandlerThread = new HandlerThread("PhoneFactoryHandlerThread");
+                pfhandlerThread.start();
                 sSubInfoRecordUpdater = new SubscriptionInfoUpdater(
-                        BackgroundThread.get().getLooper(), context, sCommandsInterfaces);
-                sc.updatePhonesAvailability(sPhones);
+                        pfhandlerThread.getLooper(), context, sCommandsInterfaces);
 
                 // Only bring up IMS if the device supports having an IMS stack.
                 if (context.getPackageManager().hasSystemFeature(
                         PackageManager.FEATURE_TELEPHONY_IMS)) {
-                    // Return whether or not the device should use dynamic binding or the static
-                    // implementation (deprecated)
-                    boolean isDynamicBinding = sContext.getResources().getBoolean(
-                            com.android.internal.R.bool.config_dynamic_bind_ims);
-                    // Get the package name of the default IMS implementation.
-                    String defaultImsPackage = sContext.getResources().getString(
-                            com.android.internal.R.string.config_ims_package);
-                    // Start ImsResolver and bind to ImsServices.
-                    Rlog.i(LOG_TAG, "ImsResolver: defaultImsPackage: " + defaultImsPackage);
-                    sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones,
-                            isDynamicBinding);
-                    sImsResolver.initialize();
                     // Start monitoring after defaults have been made.
                     // Default phone must be ready before ImsPhone is created because ImsService
-                    // might need it when it is being opened. This should initialize multiple
-                    // ImsPhones for ImsResolver implementations of ImsService.
+                    // might need it when it is being opened.
                     for (int i = 0; i < numPhones; i++) {
-                        sPhones[i].startMonitoringImsService();
+                        sPhones[i].createImsPhone();
                     }
                 } else {
                     Rlog.i(LOG_TAG, "IMS is not supported on this device, skipping ImsResolver.");
                 }
 
-                ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(
-                        ServiceManager.getService("telephony.registry"));
-
-                sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones);
-
                 sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext);
 
                 sCellularNetworkValidator = CellularNetworkValidator.make(sContext);
@@ -259,11 +228,9 @@
                 int maxActivePhones = sPhoneConfigurationManager
                         .getNumberOfModemsWithSimultaneousDataConnections();
 
-                sPhoneSwitcher = PhoneSwitcher.make(maxActivePhones, numPhones,
-                        sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces,
-                        sPhones);
+                sPhoneSwitcher = PhoneSwitcher.make(maxActivePhones, sContext, Looper.myLooper());
 
-                sProxyController = ProxyController.getInstance(context, sPhones, sPhoneSwitcher);
+                sProxyController = ProxyController.getInstance(context);
 
                 sIntentBroadcaster = IntentBroadcaster.getInstance(context);
 
@@ -271,12 +238,59 @@
 
                 for (int i = 0; i < numPhones; i++) {
                     sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
-                            sSubscriptionMonitor, Looper.myLooper(), sPhones[i]);
+                            Looper.myLooper(), sPhones[i]);
                 }
             }
         }
     }
 
+    /**
+     * Upon single SIM to dual SIM switch or vice versa, we dynamically allocate or de-allocate
+     * Phone and CommandInterface objects.
+     * @param context
+     * @param activeModemCount
+     */
+    public static void onMultiSimConfigChanged(Context context, int activeModemCount) {
+        synchronized (sLockProxyPhones) {
+            int prevActiveModemCount = sPhones.length;
+            if (prevActiveModemCount == activeModemCount) return;
+
+            // TODO: clean up sPhones, sCommandsInterfaces and sTelephonyNetworkFactories objects.
+            // Currently we will not clean up the 2nd Phone object, so that it can be re-used if
+            // user switches back.
+            if (prevActiveModemCount > activeModemCount) return;
+
+            sPhones = copyOf(sPhones, activeModemCount);
+            sCommandsInterfaces = copyOf(sCommandsInterfaces, activeModemCount);
+            sTelephonyNetworkFactories = copyOf(sTelephonyNetworkFactories, activeModemCount);
+
+            int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
+            for (int i = prevActiveModemCount; i < activeModemCount; i++) {
+                sCommandsInterfaces[i] = new RIL(context, RILConstants.PREFERRED_NETWORK_MODE,
+                        cdmaSubscription, i);
+                sPhones[i] = createPhone(context, i);
+                if (context.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_TELEPHONY_IMS)) {
+                    sPhones[i].createImsPhone();
+                }
+                sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
+                        Looper.myLooper(), sPhones[i]);
+            }
+        }
+    }
+
+    private static Phone createPhone(Context context, int phoneId) {
+        int phoneType = TelephonyManager.getPhoneType(RILConstants.PREFERRED_NETWORK_MODE);
+        Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " phoneId = " + phoneId);
+
+        // We always use PHONE_TYPE_CDMA_LTE now.
+        if (phoneType == PHONE_TYPE_CDMA) phoneType = PHONE_TYPE_CDMA_LTE;
+
+        return new GsmCdmaPhone(context,
+                sCommandsInterfaces[phoneId], sPhoneNotifier, phoneId, phoneType,
+                TelephonyComponentFactory.getInstance());
+    }
+
     @UnsupportedAppUsage
     public static Phone getDefaultPhone() {
         synchronized (sLockProxyPhones) {
@@ -331,14 +345,6 @@
     }
 
     /**
-     * @return The ImsResolver instance or null if IMS is not supported
-     * (FEATURE_TELEPHONY_IMS is not defined).
-     */
-    public static @Nullable ImsResolver getImsResolver() {
-        return sImsResolver;
-    }
-
-    /**
      * Get the network factory associated with a given phone ID.
      * @param phoneId the phone id
      * @return a factory for this phone ID, or null if none.
@@ -462,6 +468,15 @@
     }
 
     /**
+     * Get Command Interfaces.
+     */
+    public static CommandsInterface[] getCommandsInterfaces() {
+        synchronized (sLockProxyPhones) {
+            return sCommandsInterfaces;
+        }
+    }
+
+    /**
      * Adds a local log category.
      *
      * Only used within the telephony process.  Use localLog to add log entries.
@@ -528,26 +543,6 @@
             pw.println("++++++++++++++++++++++++++++++++");
         }
 
-        pw.println("ImsResolver:");
-        pw.increaseIndent();
-        try {
-            if (sImsResolver != null) sImsResolver.dump(fd, pw, args);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        pw.decreaseIndent();
-        pw.println("++++++++++++++++++++++++++++++++");
-
-        pw.println("SubscriptionMonitor:");
-        pw.increaseIndent();
-        try {
-            sSubscriptionMonitor.dump(fd, pw, args);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        pw.decreaseIndent();
-        pw.println("++++++++++++++++++++++++++++++++");
-
         pw.println("UiccController:");
         pw.increaseIndent();
         try {
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index a7f0f3e..20976df 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -17,7 +17,7 @@
 package com.android.internal.telephony;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -25,6 +25,7 @@
 import android.telecom.VideoProfile;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.PreciseDataConnectionState;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 
@@ -237,6 +238,16 @@
     DataState getDataConnectionState(String apnType);
 
     /**
+     * Get the current Precise DataState. No change notification exists at this
+     * interface -- use
+     * {@link android.telephony.PhoneStateListener} instead.
+     *
+     * @param apnType specify for which apn to get connection state info.
+     * @return the PreciseDataConnectionState for the data connection supporting apnType
+     */
+    PreciseDataConnectionState getPreciseDataConnectionState(String apnType);
+
+    /**
      * Get the current DataActivityState. No change notification exists at this
      * interface -- use
      * {@link android.telephony.TelephonyManager} instead.
@@ -424,6 +435,21 @@
     Connection dial(String dialString, @NonNull DialArgs dialArgs) throws CallStateException;
 
     /**
+     * Initiate a new conference connection. This happens asynchronously, so you
+     * cannot assume the audio path is connected (or a call index has been
+     * assigned) until PhoneStateChanged notification has occurred.
+     *
+     * @param participantsToDial The participants to dial.
+     * @param dialArgs Parameters to perform the start conference with.
+     * @exception CallStateException if a new outgoing call is not currently
+     *                possible because no more call slots exist or a call exists
+     *                that is dialing, alerting, ringing, or waiting. Other
+     *                errors are handled asynchronously.
+     */
+    Connection startConference(String[] participantsToDial, @NonNull DialArgs dialArgs)
+            throws CallStateException;
+
+    /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
      * without SEND (so <code>dial</code> is not appropriate).
      *
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 31cd71f..36fad5e 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -16,15 +16,16 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.NonNull;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.CallQuality;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
-import android.telephony.CellLocation;
 import android.telephony.PhoneCapability;
-import android.telephony.PhysicalChannelConfig;
+import android.telephony.PreciseDataConnectionState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 
@@ -39,8 +40,12 @@
 
     void notifyServiceState(Phone sender);
 
-    /** Notify registrants of the current CellLocation */
-    void notifyCellLocation(Phone sender, CellLocation cl);
+    /**
+     * Notify registrants of the current CellLocation.
+     *
+     * <p>Use CellIdentity that is Parcellable to pass AIDL; convert to CellLocation in client code.
+     */
+    void notifyCellLocation(Phone sender, CellIdentity cellIdentity);
 
     @UnsupportedAppUsage
     void notifySignalStrength(Phone sender);
@@ -50,40 +55,41 @@
 
     void notifyCallForwardingChanged(Phone sender);
 
-    void notifyDataConnection(Phone sender, String apnType, PhoneConstants.DataState state);
-
-    void notifyDataConnectionFailed(Phone sender, String apnType);
+    /** Send a notification that the Data Connection for a particular apnType has changed */
+    void notifyDataConnection(
+            Phone sender, String apnType, PreciseDataConnectionState preciseState);
 
     void notifyDataActivity(Phone sender);
 
-    void notifyOtaspChanged(Phone sender, int otaspMode);
-
     void notifyCellInfo(Phone sender, List<CellInfo> cellInfo);
 
-    /** Notify of change to PhysicalChannelConfiguration. */
-    void notifyPhysicalChannelConfiguration(Phone sender, List<PhysicalChannelConfig> configs);
-
     void notifyPreciseCallState(Phone sender);
 
     void notifyDisconnectCause(Phone sender, int cause, int preciseCause);
 
     void notifyImsDisconnectCause(Phone sender, ImsReasonInfo imsReasonInfo);
 
-    public void notifyPreciseDataConnectionFailed(Phone sender, String apnType, String apn,
+    /** Send a notification that a particular data connection has failed with specified cause. */
+    void notifyDataConnectionFailed(Phone sender, String apnType, String apn,
                                                   @DataFailureCause int failCause);
 
-    /** send a notification that the SRVCC state has changed.*/
+    /** Send a notification that the SRVCC state has changed.*/
     void notifySrvccStateChanged(Phone sender, @SrvccState int state);
 
-    public void notifyVoiceActivationStateChanged(Phone sender, int activationState);
+    /** Send a notification that the voice activation state has changed */
+    void notifyVoiceActivationStateChanged(Phone sender, int activationState);
 
-    public void notifyDataActivationStateChanged(Phone sender, int activationState);
+    /** Send a notification that the data activation state has changed */
+    void notifyDataActivationStateChanged(Phone sender, int activationState);
 
-    public void notifyUserMobileDataStateChanged(Phone sender, boolean state);
+    /** Send a notification that the users mobile data setting has changed */
+    void notifyUserMobileDataStateChanged(Phone sender, boolean state);
 
-    public void notifyOemHookRawEventForSubscriber(Phone sender, byte[] rawData);
+    /** Send a notification with an OEM hook payload */
+    void notifyOemHookRawEventForSubscriber(Phone sender, byte[] rawData);
 
-    public void notifyPhoneCapabilityChanged(PhoneCapability capability);
+    /** Send a notification that the phone capability has changed */
+    void notifyPhoneCapabilityChanged(PhoneCapability capability);
 
     void notifyRadioPowerStateChanged(Phone sender, @RadioPowerState int state);
 
@@ -98,4 +104,8 @@
 
     /** Notify of a change to the call quality of an active foreground call. */
     void notifyCallQualityChanged(Phone sender, CallQuality callQuality, int callNetworkType);
+
+    /** Notify registration failed*/
+    void notifyRegistrationFailed(Phone sender, @NonNull CellIdentity cellIdentity,
+            @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
 }
diff --git a/src/java/com/android/internal/telephony/PhoneStateIntentReceiver.java b/src/java/com/android/internal/telephony/PhoneStateIntentReceiver.java
index 1d9f4f0..6d0b03c 100644
--- a/src/java/com/android/internal/telephony/PhoneStateIntentReceiver.java
+++ b/src/java/com/android/internal/telephony/PhoneStateIntentReceiver.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -26,7 +26,8 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 /**
  *
diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
index c5b7eda..35af1b4 100644
--- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java
+++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
@@ -21,8 +21,10 @@
 import static android.Manifest.permission.MODIFY_PHONE_STATE;
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -30,12 +32,12 @@
 import android.os.ServiceManager;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 
 import com.android.internal.telephony.uicc.IsimRecords;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccCardApplication;
+import com.android.telephony.Rlog;
 
 public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
     private static final String TAG = "PhoneSubInfoController";
@@ -43,13 +45,10 @@
     private static final boolean VDBG = false; // STOPSHIP if true
 
     @UnsupportedAppUsage
-    private final Phone[] mPhone;
-    @UnsupportedAppUsage
     private final Context mContext;
     private final AppOpsManager mAppOps;
 
-    public PhoneSubInfoController(Context context, Phone[] phone) {
-        mPhone = phone;
+    public PhoneSubInfoController(Context context) {
         if (ServiceManager.getService("iphonesubinfo") == null) {
             ServiceManager.addService("iphonesubinfo", this);
         }
@@ -57,29 +56,36 @@
         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
     }
 
+    @Deprecated
     public String getDeviceId(String callingPackage) {
+        return getDeviceIdWithFeature(callingPackage, null);
+    }
+
+    public String getDeviceIdWithFeature(String callingPackage, String callingFeatureId) {
         return getDeviceIdForPhone(SubscriptionManager.getPhoneId(getDefaultSubscription()),
-                callingPackage);
+                callingPackage, callingFeatureId);
     }
 
-    public String getDeviceIdForPhone(int phoneId, String callingPackage) {
+    public String getDeviceIdForPhone(int phoneId, String callingPackage,
+            String callingFeatureId) {
         return callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(phoneId, callingPackage,
-                "getDeviceId", (phone)-> phone.getDeviceId());
+                callingFeatureId, "getDeviceId", (phone) -> phone.getDeviceId());
     }
 
-    public String getNaiForSubscriber(int subId, String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getNai",
-                (phone)-> phone.getNai());
+    public String getNaiForSubscriber(int subId, String callingPackage, String callingFeatureId) {
+        return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
+                callingFeatureId, "getNai", (phone)-> phone.getNai());
     }
 
-    public String getImeiForSubscriber(int subId, String callingPackage) {
+    public String getImeiForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         return callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(subId, callingPackage,
-                "getImei", (phone)-> phone.getImei());
+                callingFeatureId, "getImei", (phone) -> phone.getImei());
     }
 
     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType,
                                                               String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
+        return callPhoneMethodForSubIdWithPrivilegedCheck(subId,
                 "getCarrierInfoForImsiEncryption",
                 (phone)-> phone.getCarrierInfoForImsiEncryption(keyType));
     }
@@ -103,42 +109,50 @@
      */
     public void resetCarrierKeysForImsiEncryption(int subId, String callingPackage) {
         callPhoneMethodForSubIdWithModifyCheck(subId, callingPackage,
-                "setCarrierInfoForImsiEncryption",
+                "resetCarrierKeysForImsiEncryption",
                 (phone)-> {
                     phone.resetCarrierKeysForImsiEncryption();
                     return null;
                 });
     }
 
-
-    public String getDeviceSvn(String callingPackage) {
-        return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage);
+    public String getDeviceSvn(String callingPackage, String callingFeatureId) {
+        return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage, callingFeatureId);
     }
 
-    public String getDeviceSvnUsingSubId(int subId, String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getDeviceSvn",
-                (phone)-> phone.getDeviceSvn());
+    public String getDeviceSvnUsingSubId(int subId, String callingPackage,
+            String callingFeatureId) {
+        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
+                "getDeviceSvn", (phone)-> phone.getDeviceSvn());
     }
 
+    @Deprecated
     public String getSubscriberId(String callingPackage) {
-        return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage);
+        return getSubscriberIdWithFeature(callingPackage, null);
     }
 
-    public String getSubscriberIdForSubscriber(int subId, String callingPackage) {
+    public String getSubscriberIdWithFeature(String callingPackage, String callingFeatureId) {
+        return getSubscriberIdForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
+    }
+
+    public String getSubscriberIdForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         String message = "getSubscriberId";
         long identity = Binder.clearCallingIdentity();
         boolean isActive;
         try {
-            isActive = SubscriptionController.getInstance().isActiveSubId(subId, callingPackage);
+            isActive = SubscriptionController.getInstance().isActiveSubId(subId, callingPackage,
+                    callingFeatureId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
         if (isActive) {
             return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
-                    message, (phone) -> phone.getSubscriberId());
+                    callingFeatureId, message, (phone) -> phone.getSubscriberId());
         } else {
             if (!TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(
-                    mContext, subId, callingPackage, message)) {
+                    mContext, subId, callingPackage, callingFeatureId, message)) {
                 return null;
             }
             identity = Binder.clearCallingIdentity();
@@ -150,52 +164,66 @@
         }
     }
 
+    @Deprecated
+    public String getIccSerialNumber(String callingPackage) {
+        return getIccSerialNumberWithFeature(callingPackage, null);
+    }
+
     /**
      * Retrieves the serial number of the ICC, if applicable.
      */
-    public String getIccSerialNumber(String callingPackage) {
-        return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage);
+    public String getIccSerialNumberWithFeature(String callingPackage, String callingFeatureId) {
+        return getIccSerialNumberForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
-    public String getIccSerialNumberForSubscriber(int subId, String callingPackage) {
+    public String getIccSerialNumberForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         return callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(subId, callingPackage,
-                "getIccSerialNumber", (phone) -> phone.getIccSerialNumber());
+                callingFeatureId, "getIccSerialNumber", (phone) -> phone.getIccSerialNumber());
     }
 
-    public String getLine1Number(String callingPackage) {
-        return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage);
+    public String getLine1Number(String callingPackage, String callingFeatureId) {
+        return getLine1NumberForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
-    public String getLine1NumberForSubscriber(int subId, String callingPackage) {
+    public String getLine1NumberForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
         return callPhoneMethodForSubIdWithReadPhoneNumberCheck(
-                subId, callingPackage, "getLine1Number",
+                subId, callingPackage, callingFeatureId, "getLine1Number",
                 (phone)-> phone.getLine1Number());
     }
 
-    public String getLine1AlphaTag(String callingPackage) {
-        return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
+    public String getLine1AlphaTag(String callingPackage, String callingFeatureId) {
+        return getLine1AlphaTagForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
-    public String getLine1AlphaTagForSubscriber(int subId, String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getLine1AlphaTag",
-                (phone)-> phone.getLine1AlphaTag());
+    public String getLine1AlphaTagForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
+        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
+                "getLine1AlphaTag", (phone)-> phone.getLine1AlphaTag());
     }
 
-    public String getMsisdn(String callingPackage) {
-        return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage);
+    public String getMsisdn(String callingPackage, String callingFeatureId) {
+        return getMsisdnForSubscriber(getDefaultSubscription(), callingPackage, callingFeatureId);
     }
 
-    public String getMsisdnForSubscriber(int subId, String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, "getMsisdn",
-                (phone)-> phone.getMsisdn());
+    public String getMsisdnForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
+        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
+                "getMsisdn", (phone)-> phone.getMsisdn());
     }
 
-    public String getVoiceMailNumber(String callingPackage) {
-        return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage);
+    public String getVoiceMailNumber(String callingPackage, String callingFeatureId) {
+        return getVoiceMailNumberForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
-    public String getVoiceMailNumberForSubscriber(int subId, String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
+    public String getVoiceMailNumberForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
+        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
                 "getVoiceMailNumber", (phone)-> {
                     String number = PhoneNumberUtils.extractNetworkPortion(
                             phone.getVoiceMailNumber());
@@ -204,12 +232,14 @@
                 });
     }
 
-    public String getVoiceMailAlphaTag(String callingPackage) {
-        return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage);
+    public String getVoiceMailAlphaTag(String callingPackage, String callingFeatureId) {
+        return getVoiceMailAlphaTagForSubscriber(getDefaultSubscription(), callingPackage,
+                callingFeatureId);
     }
 
-    public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
+    public String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
+        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
                 "getVoiceMailAlphaTag", (phone)-> phone.getVoiceMailAlphaTag());
     }
 
@@ -222,7 +252,7 @@
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             phoneId = 0;
         }
-        return mPhone[phoneId];
+        return PhoneFactory.getPhone(phoneId);
     }
 
     /**
@@ -240,7 +270,7 @@
             return;
         }
         if (VDBG) log("No read privileged phone permission, check carrier privilege next.");
-        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, message);
+        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, subId, message);
     }
 
     /**
@@ -357,16 +387,17 @@
             return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data);
         };
 
-        return callPhoneMethodWithPermissionCheck(
-                subId, null, "getIccSimChallengeResponse", toExecute,
-                (aContext, aSubId, aCallingPackage, aMessage)-> {
+        return callPhoneMethodWithPermissionCheck(subId, null, null, "getIccSimChallengeResponse",
+                toExecute,
+                (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) -> {
                     enforcePrivilegedPermissionOrCarrierPrivilege(aSubId, aMessage);
                     return true;
                 });
     }
 
-    public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage) {
-        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage,
+    public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage,
+            String callingFeatureId) {
+        return callPhoneMethodForSubIdWithReadCheck(subId, callingPackage, callingFeatureId,
                 "getGroupIdLevel1", (phone)-> phone.getGroupIdLevel1());
     }
 
@@ -385,14 +416,17 @@
         // If passes, it should return true.
         // If permission is not granted, throws SecurityException.
         // If permission is revoked by AppOps, return false.
-        boolean checkPermission(Context context, int subId, String callingPackage, String message);
+        boolean checkPermission(Context context, int subId, String callingPackage,
+                @Nullable String callingFeatureId, String message);
     }
 
     // Base utility method that others use.
     private <T> T callPhoneMethodWithPermissionCheck(int subId, String callingPackage,
-            String message, CallPhoneMethodHelper<T> callMethodHelper,
+            @Nullable String callingFeatureId, String message,
+            CallPhoneMethodHelper<T> callMethodHelper,
             PermissionCheckHelper permissionCheckHelper) {
-        if (!permissionCheckHelper.checkPermission(mContext, subId, callingPackage, message)) {
+        if (!permissionCheckHelper.checkPermission(mContext, subId, callingPackage,
+                callingFeatureId, message)) {
             return null;
         }
 
@@ -411,34 +445,39 @@
     }
 
     private <T> T callPhoneMethodForSubIdWithReadCheck(int subId, String callingPackage,
-            String message, CallPhoneMethodHelper<T> callMethodHelper) {
-        return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
-                (aContext, aSubId, aCallingPackage, aMessage)->
+            @Nullable String callingFeatureId, String message,
+            CallPhoneMethodHelper<T> callMethodHelper) {
+        return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
+                message, callMethodHelper,
+                (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)->
                         TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                                aContext, aSubId, aCallingPackage, aMessage));
+                                aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
     }
 
     private <T> T callPhoneMethodForSubIdWithReadDeviceIdentifiersCheck(int subId,
-            String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) {
-        return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
-                (aContext, aSubId, aCallingPackage, aMessage)->
+            String callingPackage, @Nullable String callingFeatureId, String message,
+            CallPhoneMethodHelper<T> callMethodHelper) {
+        return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
+                message, callMethodHelper,
+                (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)->
                         TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(
-                                aContext, aSubId, aCallingPackage, aMessage));
+                                aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
     }
 
     private <T> T callPhoneMethodForSubIdWithReadSubscriberIdentifiersCheck(int subId,
-            String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) {
-        return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
-                (aContext, aSubId, aCallingPackage, aMessage)->
+            String callingPackage, @Nullable String callingFeatureId, String message,
+            CallPhoneMethodHelper<T> callMethodHelper) {
+        return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
+                message, callMethodHelper,
+                (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)->
                         TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(
-                                aContext, aSubId, aCallingPackage, aMessage));
+                                aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
     }
 
-
     private <T> T callPhoneMethodForSubIdWithPrivilegedCheck(
             int subId, String message, CallPhoneMethodHelper<T> callMethodHelper) {
-        return callPhoneMethodWithPermissionCheck(subId, null, message, callMethodHelper,
-                (aContext, aSubId, aCallingPackage, aMessage)-> {
+        return callPhoneMethodWithPermissionCheck(subId, null, null, message, callMethodHelper,
+                (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) -> {
                     mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, message);
                     return true;
                 });
@@ -446,33 +485,36 @@
 
     private <T> T callPhoneMethodForSubIdWithModifyCheck(int subId, String callingPackage,
             String message, CallPhoneMethodHelper<T> callMethodHelper) {
-        return callPhoneMethodWithPermissionCheck(subId, null, message, callMethodHelper,
-                (aContext, aSubId, aCallingPackage, aMessage)-> {
+        return callPhoneMethodWithPermissionCheck(subId, null, null, message, callMethodHelper,
+                (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage)-> {
                     enforceModifyPermission();
                     return true;
                 });
     }
 
     private <T> T callPhoneMethodForSubIdWithReadPhoneNumberCheck(int subId, String callingPackage,
-            String message, CallPhoneMethodHelper<T> callMethodHelper) {
-        return callPhoneMethodWithPermissionCheck(subId, callingPackage, message, callMethodHelper,
-                (aContext, aSubId, aCallingPackage, aMessage)->
+            @NonNull String callingFeatureId, String message,
+            CallPhoneMethodHelper<T> callMethodHelper) {
+        return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
+                message, callMethodHelper,
+                (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) ->
                         TelephonyPermissions.checkCallingOrSelfReadPhoneNumber(
-                                aContext, aSubId, aCallingPackage, aMessage));
+                                aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage));
     }
 
     private <T> T callPhoneMethodForPhoneIdWithReadDeviceIdentifiersCheck(int phoneId,
-            String callingPackage, String message, CallPhoneMethodHelper<T> callMethodHelper) {
+            String callingPackage, @Nullable String callingFeatureId, String message,
+            CallPhoneMethodHelper<T> callMethodHelper) {
         // Getting subId before doing permission check.
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             phoneId = 0;
         }
-        final Phone phone = mPhone[phoneId];
+        final Phone phone = PhoneFactory.getPhone(phoneId);
         if (phone == null) {
             return null;
         }
         if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
-                phone.getSubId(), callingPackage, message)) {
+                phone.getSubId(), callingPackage, callingFeatureId, message)) {
             return null;
         }
 
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index cf64a8b..bdfd925 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -25,7 +25,9 @@
 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS;
 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED;
 
-import android.annotation.UnsupportedAppUsage;
+import static java.util.Arrays.copyOf;
+
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -37,7 +39,7 @@
 import android.net.NetworkFactory;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
@@ -46,13 +48,12 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneCapability;
 import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
 import android.telephony.data.ApnSetting;
 import android.util.LocalLog;
 
@@ -62,7 +63,9 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
+import com.android.internal.telephony.util.HandlerExecutor;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -154,15 +157,10 @@
     private final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>();
     private final RegistrantList mActivePhoneRegistrants;
     private final SubscriptionController mSubscriptionController;
-    private final int[] mPhoneSubscriptions;
-    private final CommandsInterface[] mCommandsInterfaces;
     private final Context mContext;
-    private final PhoneState[] mPhoneStates;
-    @UnsupportedAppUsage
-    private final int mNumPhones;
-    @UnsupportedAppUsage
-    private final Phone[] mPhones;
     private final LocalLog mLocalLog;
+    private PhoneState[] mPhoneStates;
+    private int[] mPhoneSubscriptions;
     @VisibleForTesting
     public final PhoneStateListener mPhoneStateListener;
     private final CellularNetworkValidator mValidator;
@@ -170,8 +168,14 @@
     public final CellularNetworkValidator.ValidationCallback mValidationCallback =
             (validated, subId) -> Message.obtain(PhoneSwitcher.this,
                     EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget();
+
     @UnsupportedAppUsage
-    private int mMaxActivePhones;
+    // How many phones (correspondingly logical modems) are allowed for PS attach. This is used
+    // when we specifically use setDataAllowed to initiate on-demand PS(data) attach for each phone.
+    private int mMaxDataAttachModemCount;
+    // Local cache of TelephonyManager#getActiveModemCount(). 1 if in single SIM mode, 2 if in dual
+    // SIM mode.
+    private int mActiveModemCount;
     private static PhoneSwitcher sPhoneSwitcher = null;
 
     // Which primary (non-opportunistic) subscription is set as data subscription among all primary
@@ -237,6 +241,9 @@
     private static final int EVENT_OVERRIDE_DDS_FOR_EMERGENCY     = 115;
     // If it exists, remove the current mEmergencyOverride DDS override.
     private static final int EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE  = 116;
+    // If it exists, remove the current mEmergencyOverride DDS override.
+    @VisibleForTesting
+    public static final int EVENT_MULTI_SIM_CONFIG_CHANGED        = 117;
 
     // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's
     // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse
@@ -288,47 +295,21 @@
     /**
      * Method to create singleton instance.
      */
-    public static PhoneSwitcher make(int maxActivePhones, int numPhones, Context context,
-            SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr,
-            CommandsInterface[] cis, Phone[] phones) {
+    public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper) {
         if (sPhoneSwitcher == null) {
-            sPhoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones, context,
-                    subscriptionController, looper, tr, cis, phones);
+            sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper);
         }
 
         return sPhoneSwitcher;
     }
 
-    /** This constructor is only used for testing purpose. */
-    @VisibleForTesting
-    public PhoneSwitcher(int numPhones, Looper looper) {
-        super(looper);
-        mMaxActivePhones = 0;
-        mSubscriptionController = null;
-        mCommandsInterfaces = null;
-        mContext = null;
-        mPhoneStates = null;
-        mPhones = null;
-        mLocalLog = null;
-        mActivePhoneRegistrants = null;
-        mNumPhones = numPhones;
-        mPhoneSubscriptions = new int[numPhones];
-        mRadioConfig = RadioConfig.getInstance(mContext);
-        mPhoneStateListener = new PhoneStateListener(looper) {
-            public void onPhoneCapabilityChanged(PhoneCapability capability) {
-                onPhoneCapabilityChangedInternal(capability);
-            }
-        };
-        mValidator = CellularNetworkValidator.getInstance();
-    }
-
     private boolean isPhoneInVoiceCallChanged() {
         int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall;
         // If there's no active call, the value will become INVALID_PHONE_INDEX
         // and internet data will be switched back to system selected or user selected
         // subscription.
         mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX;
-        for (Phone phone : mPhones) {
+        for (Phone phone : PhoneFactory.getPhones()) {
             if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) {
                 mPhoneIdInVoiceCall = phone.getPhoneId();
                 break;
@@ -345,21 +326,19 @@
     }
 
     @VisibleForTesting
-    public PhoneSwitcher(int maxActivePhones, int numPhones, Context context,
-            SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr,
-            CommandsInterface[] cis, Phone[] phones) {
+    public PhoneSwitcher(int maxActivePhones, Context context, Looper looper) {
         super(looper);
         mContext = context;
-        mNumPhones = numPhones;
-        mPhones = phones;
-        mPhoneSubscriptions = new int[numPhones];
-        mMaxActivePhones = maxActivePhones;
+        mActiveModemCount = getTm().getActiveModemCount();
+        mPhoneSubscriptions = new int[mActiveModemCount];
+        mPhoneStates = new PhoneState[mActiveModemCount];
+        mMaxDataAttachModemCount = maxActivePhones;
         mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES);
 
-        mSubscriptionController = subscriptionController;
+        mSubscriptionController = SubscriptionController.getInstance();
         mRadioConfig = RadioConfig.getInstance(mContext);
 
-        mPhoneStateListener = new PhoneStateListener(looper) {
+        mPhoneStateListener = new PhoneStateListener(new HandlerExecutor(this)) {
             @Override
             public void onPhoneCapabilityChanged(PhoneCapability capability) {
                 onPhoneCapabilityChangedInternal(capability);
@@ -369,34 +348,31 @@
         mValidator = CellularNetworkValidator.getInstance();
 
         mActivePhoneRegistrants = new RegistrantList();
-        mPhoneStates = new PhoneState[numPhones];
-        for (int i = 0; i < numPhones; i++) {
+        for (int i = 0; i < mActiveModemCount; i++) {
             mPhoneStates[i] = new PhoneState();
-            if (mPhones[i] != null) {
-                mPhones[i].registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null);
+            if (PhoneFactory.getPhone(i) != null) {
+                PhoneFactory.getPhone(i).registerForEmergencyCallToggle(
+                        this, EVENT_EMERGENCY_TOGGLE, null);
                 // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone.
-                mPhones[i].registerForPreciseCallStateChanged(
+                PhoneFactory.getPhone(i).registerForPreciseCallStateChanged(
                         this, EVENT_PRECISE_CALL_STATE_CHANGED, null);
-                if (mPhones[i].getImsPhone() != null) {
-                    mPhones[i].getImsPhone().registerForPreciseCallStateChanged(
+                if (PhoneFactory.getPhone(i).getImsPhone() != null) {
+                    PhoneFactory.getPhone(i).getImsPhone().registerForPreciseCallStateChanged(
                             this, EVENT_PRECISE_CALL_STATE_CHANGED, null);
                 }
-                mPhones[i].getDataEnabledSettings().registerForDataEnabledChanged(
+                PhoneFactory.getPhone(i).getDataEnabledSettings().registerForDataEnabledChanged(
                         this, EVENT_DATA_ENABLED_CHANGED, null);
             }
         }
 
-        mCommandsInterfaces = cis;
-
-        if (numPhones > 0) {
-            mCommandsInterfaces[0].registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+        if (mActiveModemCount > 0) {
+            PhoneFactory.getPhone(0).mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
         }
 
-        try {
-            tr.addOnSubscriptionsChangedListener(context.getOpPackageName(),
-                    mSubscriptionsChangedListener);
-        } catch (RemoteException e) {
-        }
+        TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)
+                context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
+        telephonyRegistryManager.addOnSubscriptionsChangedListener(
+                mSubscriptionsChangedListener, mSubscriptionsChangedListener.getHandlerExecutor());
 
         mConnectivityManager =
             (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -404,6 +380,9 @@
         mContext.registerReceiver(mDefaultDataChangedReceiver,
                 new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED));
 
+        PhoneConfigurationManager.registerForMultiSimConfigChange(
+                this, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
+
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addTransportType(TRANSPORT_CELLULAR);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
@@ -438,8 +417,8 @@
         }
     };
 
-    private final IOnSubscriptionsChangedListener mSubscriptionsChangedListener =
-            new IOnSubscriptionsChangedListener.Stub() {
+    private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener =
+            new SubscriptionManager.OnSubscriptionsChangedListener() {
         @Override
         public void onSubscriptionsChanged() {
             Message msg = PhoneSwitcher.this.obtainMessage(EVENT_SUBSCRIPTION_CHANGED);
@@ -619,11 +598,43 @@
                 onEvaluate(REQUESTS_UNCHANGED, "emer_rm_override_dds");
                 break;
             }
+            case EVENT_MULTI_SIM_CONFIG_CHANGED: {
+                int activeModemCount = (int) ((AsyncResult) msg.obj).result;
+                onMultiSimConfigChanged(activeModemCount);
+                break;
+            }
+        }
+    }
+
+    private synchronized void onMultiSimConfigChanged(int activeModemCount) {
+        // No change.
+        if (mActiveModemCount == activeModemCount) return;
+        int oldActiveModemCount = mActiveModemCount;
+        mActiveModemCount = activeModemCount;
+
+        mPhoneSubscriptions = copyOf(mPhoneSubscriptions, mActiveModemCount);
+        mPhoneStates = copyOf(mPhoneStates, mActiveModemCount);
+
+        // Single SIM -> dual SIM switch.
+        for (int phoneId = oldActiveModemCount; phoneId < mActiveModemCount; phoneId++) {
+            mPhoneStates[phoneId] = new PhoneState();
+            Phone phone = PhoneFactory.getPhone(phoneId);
+            if (phone == null) continue;
+
+            phone.registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null);
+            // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone.
+            phone.registerForPreciseCallStateChanged(this, EVENT_PRECISE_CALL_STATE_CHANGED, null);
+            if (phone.getImsPhone() != null) {
+                phone.getImsPhone().registerForPreciseCallStateChanged(
+                        this, EVENT_PRECISE_CALL_STATE_CHANGED, null);
+            }
+            phone.getDataEnabledSettings().registerForDataEnabledChanged(
+                    this, EVENT_DATA_ENABLED_CHANGED, null);
         }
     }
 
     private boolean isInEmergencyCallbackMode() {
-        for (Phone p : mPhones) {
+        for (Phone p : PhoneFactory.getPhones()) {
             if (p == null) continue;
             if (p.isInEcm()) return true;
             Phone imsPhone = p.getImsPhone();
@@ -698,7 +709,7 @@
     private void collectRequestNetworkMetrics(NetworkRequest networkRequest) {
         // Request network for MMS will temporary disable the network on default data subscription,
         // this only happen on multi-sim device.
-        if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability(
+        if (mActiveModemCount > 1 && networkRequest.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMS)) {
             OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch();
             onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS;
@@ -710,7 +721,7 @@
     private void collectReleaseNetworkMetrics(NetworkRequest networkRequest) {
         // Release network for MMS will recover the network on default data subscription, this only
         // happen on multi-sim device.
-        if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability(
+        if (mActiveModemCount > 1 && networkRequest.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMS)) {
             OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch();
             onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS;
@@ -719,6 +730,10 @@
         }
     }
 
+    private TelephonyManager getTm() {
+        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
     private static final boolean REQUESTS_CHANGED   = true;
     private static final boolean REQUESTS_UNCHANGED = false;
     /**
@@ -748,7 +763,7 @@
         boolean hasAnyActiveSubscription = false;
 
         // Check if phoneId to subId mapping is changed.
-        for (int i = 0; i < mNumPhones; i++) {
+        for (int i = 0; i < mActiveModemCount; i++) {
             int sub = mSubscriptionController.getSubIdUsingPhoneId(i);
 
             if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true;
@@ -789,7 +804,7 @@
                 // With HAL_COMMAND_PREFERRED_DATA, all phones are assumed to allow PS attach.
                 // So marking all phone as active, and the phone with mPreferredDataPhoneId
                 // will send radioConfig command.
-                for (int phoneId = 0; phoneId < mNumPhones; phoneId++) {
+                for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) {
                     mPhoneStates[phoneId].active = true;
                 }
                 sendRilCommands(mPreferredDataPhoneId);
@@ -801,9 +816,9 @@
                  * Otherwise, choose to activate phones according to requests. And
                  * if list is not full, add mPreferredDataPhoneId.
                  */
-                if (mMaxActivePhones == mPhones.length) {
-                    for (int i = 0; i < mMaxActivePhones; i++) {
-                        newActivePhones.add(mPhones[i].getPhoneId());
+                if (mMaxDataAttachModemCount == mActiveModemCount) {
+                    for (int i = 0; i < mMaxDataAttachModemCount; i++) {
+                        newActivePhones.add(i);
                     }
                 } else {
                     // First try to activate phone in voice call.
@@ -811,17 +826,17 @@
                         newActivePhones.add(mPhoneIdInVoiceCall);
                     }
 
-                    if (newActivePhones.size() < mMaxActivePhones) {
+                    if (newActivePhones.size() < mMaxDataAttachModemCount) {
                         for (DcRequest dcRequest : mPrioritizedDcRequests) {
                             int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest);
                             if (phoneIdForRequest == INVALID_PHONE_INDEX) continue;
                             if (newActivePhones.contains(phoneIdForRequest)) continue;
                             newActivePhones.add(phoneIdForRequest);
-                            if (newActivePhones.size() >= mMaxActivePhones) break;
+                            if (newActivePhones.size() >= mMaxDataAttachModemCount) break;
                         }
                     }
 
-                    if (newActivePhones.size() < mMaxActivePhones
+                    if (newActivePhones.size() < mMaxDataAttachModemCount
                             && newActivePhones.contains(mPreferredDataPhoneId)
                             && SubscriptionManager.isUsableSubIdValue(mPreferredDataPhoneId)) {
                         newActivePhones.add(mPreferredDataPhoneId);
@@ -831,14 +846,14 @@
                 if (VDBG) {
                     log("mPrimaryDataSubId = " + mPrimaryDataSubId);
                     log("mOpptDataSubId = " + mOpptDataSubId);
-                    for (int i = 0; i < mNumPhones; i++) {
+                    for (int i = 0; i < mActiveModemCount; i++) {
                         log(" phone[" + i + "] using sub[" + mPhoneSubscriptions[i] + "]");
                     }
                     log(" newActivePhones:");
                     for (Integer i : newActivePhones) log("  " + i);
                 }
 
-                for (int phoneId = 0; phoneId < mNumPhones; phoneId++) {
+                for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) {
                     if (!newActivePhones.contains(phoneId)) {
                         deactivate(phoneId);
                     }
@@ -887,7 +902,7 @@
      * want to resend setDataAllowed or setPreferredDataSubscriptionId
      */
     public void onRadioCapChanged(int phoneId) {
-        validatePhoneId(phoneId);
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) return;
         Message msg = obtainMessage(EVENT_RADIO_CAPABILITY_CHANGED);
         msg.arg1 = phoneId;
         msg.sendToTarget();
@@ -912,7 +927,7 @@
      */
     public void overrideDefaultDataForEmergency(int phoneId, int overrideTimeSec,
             CompletableFuture<Boolean> dataSwitchResult) {
-        validatePhoneId(phoneId);
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) return;
         Message msg = obtainMessage(EVENT_OVERRIDE_DDS_FOR_EMERGENCY);
         EmergencyOverrideRequest request  = new EmergencyOverrideRequest();
         request.mPhoneId = phoneId;
@@ -923,13 +938,13 @@
     }
 
     private void sendRilCommands(int phoneId) {
-        if (!SubscriptionManager.isValidPhoneId(phoneId) || phoneId >= mNumPhones) return;
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) return;
 
         Message message = Message.obtain(this, EVENT_MODEM_COMMAND_DONE, phoneId);
         if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) {
             // Skip ALLOW_DATA for single SIM device
-            if (mNumPhones > 1) {
-                mCommandsInterfaces[phoneId].setDataAllowed(isPhoneActive(phoneId), message);
+            if (mActiveModemCount > 1) {
+                PhoneFactory.getPhone(phoneId).mCi.setDataAllowed(isPhoneActive(phoneId), message);
             }
         } else if (phoneId == mPreferredDataPhoneId) {
             // Only setPreferredDataModem if the phoneId equals to current mPreferredDataPhoneId.
@@ -938,23 +953,23 @@
     }
 
     private void onPhoneCapabilityChangedInternal(PhoneCapability capability) {
-        int newMaxActivePhones = TelephonyManager.getDefault()
+        int newMaxDataAttachModemCount = TelephonyManager.getDefault()
                 .getNumberOfModemsWithSimultaneousDataConnections();
-        if (mMaxActivePhones != newMaxActivePhones) {
-            mMaxActivePhones = newMaxActivePhones;
-            log("Max active phones changed to " + mMaxActivePhones);
+        if (mMaxDataAttachModemCount != newMaxDataAttachModemCount) {
+            mMaxDataAttachModemCount = newMaxDataAttachModemCount;
+            log("Max active phones changed to " + mMaxDataAttachModemCount);
             onEvaluate(REQUESTS_UNCHANGED, "phoneCfgChanged");
         }
     }
 
     private int phoneIdForRequest(NetworkRequest netRequest) {
-        int subId = getSubIdFromNetworkSpecifier(netRequest.networkCapabilities
-                .getNetworkSpecifier());
+        int subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier());
 
         if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId;
         if (subId == INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX;
 
-        int preferredDataSubId = SubscriptionManager.isValidPhoneId(mPreferredDataPhoneId)
+        int preferredDataSubId = (mPreferredDataPhoneId >= 0
+                && mPreferredDataPhoneId < mActiveModemCount)
                 ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID;
 
         // Currently we assume multi-SIM devices will only support one Internet PDN connection. So
@@ -972,7 +987,7 @@
 
         // Try to find matching phone ID. If it doesn't exist, we'll end up returning INVALID.
         int phoneId = INVALID_PHONE_INDEX;
-        for (int i = 0; i < mNumPhones; i++) {
+        for (int i = 0; i < mActiveModemCount; i++) {
             if (mPhoneSubscriptions[i] == subId) {
                 phoneId = i;
                 break;
@@ -985,22 +1000,10 @@
         if (specifier == null) {
             return DEFAULT_SUBSCRIPTION_ID;
         }
-
-        int subId;
-
-        if (specifier instanceof StringNetworkSpecifier) {
-            try {
-                subId = Integer.parseInt(((StringNetworkSpecifier) specifier).specifier);
-            } catch (NumberFormatException e) {
-                Rlog.e(LOG_TAG, "NumberFormatException on "
-                        + ((StringNetworkSpecifier) specifier).specifier);
-                return INVALID_SUBSCRIPTION_ID;
-            }
-        } else {
-            return INVALID_SUBSCRIPTION_ID;
+        if (specifier instanceof TelephonyNetworkSpecifier) {
+            return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
         }
-
-        return subId;
+        return INVALID_SUBSCRIPTION_ID;
     }
 
     private int getSubIdForDefaultNetworkRequests() {
@@ -1035,7 +1038,7 @@
             int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
 
             if (SubscriptionManager.isUsableSubIdValue(subId)) {
-                for (int i = 0; i < mNumPhones; i++) {
+                for (int i = 0; i < mActiveModemCount; i++) {
                     if (mPhoneSubscriptions[i] == subId) {
                         phoneId = i;
                         break;
@@ -1050,7 +1053,7 @@
     }
 
     private void transitionToEmergencyPhone() {
-        if (mNumPhones <= 0) {
+        if (mActiveModemCount <= 0) {
             log("No phones: unable to reset preferred phone for emergency");
             return;
         }
@@ -1067,14 +1070,15 @@
     }
 
     private Phone findPhoneById(final int phoneId) {
-        if (phoneId < 0 || phoneId >= mNumPhones) {
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             return null;
         }
-        return mPhones[phoneId];
+        return PhoneFactory.getPhone(phoneId);
     }
 
-    public boolean shouldApplyNetworkRequest(NetworkRequest networkRequest, int phoneId) {
-        validatePhoneId(phoneId);
+    public synchronized boolean shouldApplyNetworkRequest(
+            NetworkRequest networkRequest, int phoneId) {
+        if (!SubscriptionManager.isValidPhoneId(phoneId)) return false;
 
         // In any case, if phone state is inactive, don't apply the network request.
         if (!isPhoneActive(phoneId) || (
@@ -1094,6 +1098,8 @@
 
     @VisibleForTesting
     protected boolean isPhoneActive(int phoneId) {
+        if (phoneId >= mActiveModemCount)
+            return false;
         return mPhoneStates[phoneId].active;
     }
 
@@ -1111,13 +1117,6 @@
         mActivePhoneRegistrants.remove(h);
     }
 
-    @VisibleForTesting
-    protected void validatePhoneId(int phoneId) {
-        if (phoneId < 0 || phoneId >= mNumPhones) {
-            throw new IllegalArgumentException("Invalid PhoneId");
-        }
-    }
-
     /**
      * Set opportunistic data subscription. It's an indication to switch Internet data to this
      * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate
@@ -1301,14 +1300,10 @@
      * See {@link PhoneStateListener#LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE}.
      */
     private void notifyPreferredDataSubIdChanged() {
-        ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
-                "telephony.registry"));
-        try {
-            log("notifyPreferredDataSubIdChanged to " + mPreferredDataSubId);
-            tr.notifyActiveDataSubIdChanged(mPreferredDataSubId);
-        } catch (RemoteException ex) {
-            // Should never happen because its always available.
-        }
+        TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext
+                .getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
+        log("notifyPreferredDataSubIdChanged to " + mPreferredDataSubId);
+        telephonyRegistryManager.notifyActiveDataSubIdChanged(mPreferredDataSubId);
     }
 
     /**
@@ -1322,7 +1317,7 @@
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
         pw.println("PhoneSwitcher:");
         Calendar c = Calendar.getInstance();
-        for (int i = 0; i < mNumPhones; i++) {
+        for (int i = 0; i < mActiveModemCount; i++) {
             PhoneState ps = mPhoneStates[i];
             c.setTimeInMillis(ps.lastRequested);
             pw.println("PhoneId(" + i + ") active=" + ps.active + ", lastRequest=" +
diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java
index 54fcac9..d6ed87b 100644
--- a/src/java/com/android/internal/telephony/ProxyController.java
+++ b/src/java/com/android/internal/telephony/ProxyController.java
@@ -16,7 +16,9 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import static java.util.Arrays.copyOf;
+
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncResult;
@@ -25,12 +27,12 @@
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.telephony.RadioAccessFamily;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import com.android.internal.telephony.ims.RcsMessageController;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -40,11 +42,13 @@
 public class ProxyController {
     static final String LOG_TAG = "ProxyController";
 
-    private static final int EVENT_NOTIFICATION_RC_CHANGED        = 1;
+    private static final int EVENT_NOTIFICATION_RC_CHANGED  = 1;
     private static final int EVENT_START_RC_RESPONSE        = 2;
     private static final int EVENT_APPLY_RC_RESPONSE        = 3;
     private static final int EVENT_FINISH_RC_RESPONSE       = 4;
     private static final int EVENT_TIMEOUT                  = 5;
+    @VisibleForTesting
+    public static final int EVENT_MULTI_SIM_CONFIG_CHANGED  = 6;
 
     private static final int SET_RC_STATUS_IDLE             = 0;
     private static final int SET_RC_STATUS_STARTING         = 1;
@@ -105,9 +109,9 @@
 
 
     //***** Class Methods
-    public static ProxyController getInstance(Context context, Phone[] phone, PhoneSwitcher ps) {
+    public static ProxyController getInstance(Context context) {
         if (sProxyController == null) {
-            sProxyController = new ProxyController(context, phone, ps);
+            sProxyController = new ProxyController(context);
         }
         return sProxyController;
     }
@@ -117,17 +121,15 @@
         return sProxyController;
     }
 
-    private ProxyController(Context context, Phone[] phone, PhoneSwitcher phoneSwitcher) {
+    private ProxyController(Context context) {
         logd("Constructor - Enter");
 
         mContext = context;
-        mPhones = phone;
-        mPhoneSwitcher = phoneSwitcher;
+        mPhones = PhoneFactory.getPhones();
+        mPhoneSwitcher = PhoneSwitcher.getInstance();
 
-        RcsMessageController.init(context);
-
-        mUiccPhoneBookController = new UiccPhoneBookController(mPhones);
-        mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones);
+        mUiccPhoneBookController = new UiccPhoneBookController();
+        mPhoneSubInfoController = new PhoneSubInfoController(mContext);
         mSmsController = new SmsController(mContext);
         mSetRadioAccessFamilyStatus = new int[mPhones.length];
         mNewRadioAccessFamily = new int[mPhones.length];
@@ -146,6 +148,9 @@
             mPhones[i].registerForRadioCapabilityChanged(
                     mHandler, EVENT_NOTIFICATION_RC_CHANGED, null);
         }
+
+        PhoneConfigurationManager.registerForMultiSimConfigChange(
+                mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
         logd("Constructor - Exit");
     }
 
@@ -201,7 +206,7 @@
      */
     public boolean setRadioCapability(RadioAccessFamily[] rafs) {
         if (rafs.length != mPhones.length) {
-            throw new RuntimeException("Length of input rafs must equal to total phone count");
+            return false;
         }
         // Check if there is any ongoing transaction and throw an exception if there
         // is one as this is a programming error.
@@ -291,7 +296,8 @@
         return true;
     }
 
-    private Handler mHandler = new Handler() {
+    @VisibleForTesting
+    public final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             logd("handleMessage msg.what=" + msg.what);
@@ -316,12 +322,37 @@
                     onTimeoutRadioCapability(msg);
                     break;
 
+                case EVENT_MULTI_SIM_CONFIG_CHANGED:
+                    onMultiSimConfigChanged();
+                    break;
+
                 default:
                     break;
             }
         }
     };
 
+    private void onMultiSimConfigChanged() {
+        int oldPhoneCount = mPhones.length;
+        mPhones = PhoneFactory.getPhones();
+
+        // Re-size arrays.
+        mSetRadioAccessFamilyStatus = copyOf(mSetRadioAccessFamilyStatus, mPhones.length);
+        mNewRadioAccessFamily = copyOf(mNewRadioAccessFamily, mPhones.length);
+        mOldRadioAccessFamily = copyOf(mOldRadioAccessFamily, mPhones.length);
+        mCurrentLogicalModemIds = copyOf(mCurrentLogicalModemIds, mPhones.length);
+        mNewLogicalModemIds = copyOf(mNewLogicalModemIds, mPhones.length);
+
+        // Clear to be sure we're in the initial state
+        clearTransaction();
+
+        // Register radio cap change for new phones.
+        for (int i = oldPhoneCount; i < mPhones.length; i++) {
+            mPhones[i].registerForRadioCapabilityChanged(
+                    mHandler, EVENT_NOTIFICATION_RC_CHANGED, null);
+        }
+    }
+
     /**
      * Handle START response
      * @param msg obj field isa RadioCapability
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 4d7a687..b812432 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -19,7 +19,7 @@
 import static com.android.internal.telephony.RILConstants.*;
 import static com.android.internal.util.Preconditions.checkNotNull;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.hardware.radio.V1_0.Carrier;
 import android.hardware.radio.V1_0.CarrierRestrictions;
@@ -48,17 +48,16 @@
 import android.hardware.radio.V1_0.SimApdu;
 import android.hardware.radio.V1_0.SmsWriteArgs;
 import android.hardware.radio.V1_0.UusInfo;
-import android.hardware.radio.V1_2.AccessNetwork;
 import android.hardware.radio.V1_4.CarrierRestrictionsWithPriority;
 import android.hardware.radio.V1_4.SimLockMultiSimPolicy;
+import android.hardware.radio.V1_5.AccessNetwork;
+import android.hardware.radio.V1_5.RadioAccessNetworks;
 import android.hardware.radio.deprecated.V1_0.IOemHook;
-import android.net.ConnectivityManager;
+import android.net.InetAddresses;
 import android.net.KeepalivePacketData;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.NetworkUtils;
 import android.os.AsyncResult;
-import android.os.Build;
 import android.os.Handler;
 import android.os.HwBinder;
 import android.os.Message;
@@ -66,10 +65,10 @@
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.service.carrier.CarrierIdentifier;
+import android.sysprop.TelephonyProperties;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.CarrierRestrictionRules;
 import android.telephony.CellInfo;
@@ -87,10 +86,11 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.RadioAccessFamily;
 import android.telephony.RadioAccessSpecifier;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyHistogram;
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyManager.PrefNetworkMode;
@@ -112,6 +112,8 @@
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
 import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
@@ -129,6 +131,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 
 /**
  * RIL implementation of the CommandsInterface.
@@ -179,6 +182,9 @@
     /** @hide */
     public static final HalVersion RADIO_HAL_VERSION_1_4 = new HalVersion(1, 4);
 
+    /** @hide */
+    public static final HalVersion RADIO_HAL_VERSION_1_5 = new HalVersion(1, 5);
+
     // IRadio version
     private HalVersion mRadioVersion = RADIO_HAL_VERSION_UNKNOWN;
 
@@ -233,7 +239,7 @@
     /** Radio bug detector instance */
     private RadioBugDetector mRadioBugDetector = null;
 
-    boolean mIsMobileNetworkSupported;
+    boolean mIsCellularSupported;
     RadioResponse mRadioResponse;
     RadioIndication mRadioIndication;
     volatile IRadio mRadioProxy = null;
@@ -378,7 +384,7 @@
         switch(rr.mRequest) {
             case RIL_REQUEST_GET_ACTIVITY_INFO:
                 timeoutResponse = new ModemActivityInfo(
-                        0, 0, 0, new int [ModemActivityInfo.TX_POWER_LEVELS], 0, 0);
+                        0, 0, 0, new int [ModemActivityInfo.TX_POWER_LEVELS], 0);
                 break;
         };
         return timeoutResponse;
@@ -413,8 +419,8 @@
     /** Returns a {@link IRadio} instance or null if the service is not available. */
     @VisibleForTesting
     public synchronized IRadio getRadioProxy(Message result) {
-        if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null;
-        if (!mIsMobileNetworkSupported) {
+        if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return null;
+        if (!mIsCellularSupported) {
             if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only");
             if (result != null) {
                 AsyncResult.forMessage(result, null,
@@ -434,14 +440,23 @@
                         + " is disabled");
             } else {
                 try {
-                    mRadioProxy = android.hardware.radio.V1_4.IRadio.getService(
+                    mRadioProxy = android.hardware.radio.V1_5.IRadio.getService(
                             HIDL_SERVICE_NAME[mPhoneId], true);
-                    mRadioVersion = RADIO_HAL_VERSION_1_4;
+                    mRadioVersion = RADIO_HAL_VERSION_1_5;
                 } catch (NoSuchElementException e) {
                 }
 
                 if (mRadioProxy == null) {
                     try {
+                        mRadioProxy = android.hardware.radio.V1_4.IRadio.getService(
+                                HIDL_SERVICE_NAME[mPhoneId], true);
+                        mRadioVersion = RADIO_HAL_VERSION_1_4;
+                    } catch (NoSuchElementException e) {
+                    }
+                }
+
+                if (mRadioProxy == null) {
+                    try {
                         mRadioProxy = android.hardware.radio.V1_3.IRadio.getService(
                                 HIDL_SERVICE_NAME[mPhoneId], true);
                         mRadioVersion = RADIO_HAL_VERSION_1_3;
@@ -510,14 +525,16 @@
             // Try to connect to RIL services and set response functions.
             getRadioProxy(null);
             getOemHookProxy(null);
+        } else {
+            resetProxyAndRequestList();
         }
     }
 
     /** Returns an {@link IOemHook} instance or null if the service is not available. */
     @VisibleForTesting
     public synchronized IOemHook getOemHookProxy(Message result) {
-        if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null;
-        if (!mIsMobileNetworkSupported) {
+        if (!SubscriptionManager.isValidPhoneId((mPhoneId))) return null;
+        if (!mIsCellularSupported) {
             if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only");
             if (result != null) {
                 AsyncResult.forMessage(result, null,
@@ -591,9 +608,9 @@
             mRadioBugDetector = new RadioBugDetector(context, mPhoneId);
         }
 
-        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        mIsMobileNetworkSupported = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        TelephonyManager tm = (TelephonyManager) context.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        mIsCellularSupported = tm.isVoiceCapable() || tm.isSmsCapable() || tm.isDataCapable();
 
         mRadioResponse = new RadioResponse(this);
         mRadioIndication = new RadioIndication(this);
@@ -607,10 +624,10 @@
         mWakeLock.setReferenceCounted(false);
         mAckWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_ACK_WAKELOCK_NAME);
         mAckWakeLock.setReferenceCounted(false);
-        mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT,
-                DEFAULT_WAKE_LOCK_TIMEOUT_MS);
-        mAckWakeLockTimeout = SystemProperties.getInt(
-                TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT, DEFAULT_ACK_WAKE_LOCK_TIMEOUT_MS);
+        mWakeLockTimeout = TelephonyProperties.wake_lock_timeout()
+                .orElse(DEFAULT_WAKE_LOCK_TIMEOUT_MS);
+        mAckWakeLockTimeout = TelephonyProperties.wake_lock_timeout()
+                .orElse(DEFAULT_ACK_WAKE_LOCK_TIMEOUT_MS);
         mWakeLockCount = 0;
         mRILDefaultWorkSource = new WorkSource(context.getApplicationInfo().uid,
                 context.getPackageName());
@@ -1423,7 +1440,7 @@
         // ServiceState.RIL_RADIO_TECHNOLOGY_XXXX.
         dpi.bearerBitmap = ServiceState.convertNetworkTypeBitmaskToBearerBitmask(
                 dp.getBearerBitmask()) << 1;
-        dpi.mtu = dp.getMtu();
+        dpi.mtu = dp.getMtuV4();
         dpi.mvnoType = MvnoType.NONE;
         dpi.mvnoMatchData = "";
 
@@ -1457,7 +1474,45 @@
         // ServiceState.RIL_RADIO_TECHNOLOGY_XXXX.
         dpi.bearerBitmap = ServiceState.convertNetworkTypeBitmaskToBearerBitmask(
                 dp.getBearerBitmask()) << 1;
-        dpi.mtu = dp.getMtu();
+        dpi.mtu = dp.getMtuV4();
+        dpi.persistent = dp.isPersistent();
+        dpi.preferred = dp.isPreferred();
+
+        // profile id is only meaningful when it's persistent on the modem.
+        dpi.profileId = (dpi.persistent) ? dp.getProfileId() : DataProfileId.INVALID;
+
+        return dpi;
+    }
+
+    /**
+     * 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.apn = dp.getApn();
+        dpi.protocol = dp.getProtocolType();
+        dpi.roamingProtocol = dp.getRoamingProtocolType();
+        dpi.authType = dp.getAuthType();
+        dpi.user = dp.getUserName();
+        dpi.password = dp.getPassword();
+        dpi.type = dp.getType();
+        dpi.maxConnsTime = dp.getMaxConnectionsTime();
+        dpi.maxConns = dp.getMaxConnections();
+        dpi.waitTime = dp.getWaitTime();
+        dpi.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.bearerBitmap = ServiceState.convertNetworkTypeBitmaskToBearerBitmask(
+            dp.getBearerBitmask()) << 1;
+        dpi.mtuV4 = dp.getMtuV4();
+        dpi.mtuV6 = dp.getMtuV6();
         dpi.persistent = dp.isPersistent();
         dpi.preferred = dp.isPreferred();
 
@@ -1511,7 +1566,40 @@
             }
 
             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);
+
+                    ArrayList<android.hardware.radio.V1_5.LinkAddress> addresses15 =
+                            new ArrayList<>();
+                    if (linkProperties != null) {
+                        for (LinkAddress la : linkProperties.getAllLinkAddresses()) {
+                            android.hardware.radio.V1_5.LinkAddress linkAddress =
+                                    new android.hardware.radio.V1_5.LinkAddress();
+                            linkAddress.address = la.getAddress().getHostAddress();
+                            linkAddress.properties = la.getFlags();
+                            linkAddress.deprecationTime = la.getDeprecationTime();
+                            linkAddress.expirationTime = la.getExpirationTime();
+                            addresses15.add(linkAddress);
+                        }
+                    }
+
+                    if (RILJ_LOGD) {
+                        riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                                + ",accessNetworkType="
+                                + AccessNetworkType.toString(accessNetworkType) + ",isRoaming="
+                                + isRoaming + ",allowRoaming=" + allowRoaming + "," + dataProfile
+                                + ",addresses=" + addresses15 + ",dnses=" + dnses);
+                    }
+
+                    radioProxy15.setupDataCall_1_5(rr.mSerial, accessNetworkType, dpi, allowRoaming,
+                            reason, addresses15, 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;
@@ -1600,7 +1688,7 @@
                     mRILDefaultWorkSource);
 
             if (RILJ_LOGD) {
-                if (Build.IS_DEBUGGABLE) {
+                if (TelephonyUtils.IS_DEBUGGABLE) {
                     riljLog(rr.serialString() + "> iccIO: "
                             + requestToString(rr.mRequest) + " command = 0x"
                             + Integer.toHexString(command) + " fileId = 0x"
@@ -2004,20 +2092,31 @@
     }
 
     @Override
-    public void setNetworkSelectionModeManual(String operatorNumeric, Message result) {
+    public void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
             RILRequest rr = obtainRequest(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, result,
                     mRILDefaultWorkSource);
-
-            if (RILJ_LOGD) {
-                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
-                        + " operatorNumeric = " + operatorNumeric);
-            }
-
             try {
-                radioProxy.setNetworkSelectionModeManual(rr.mSerial,
-                        convertNullToEmptyString(operatorNumeric));
+                int accessNetwork = convertRanToAnt(ran);
+                if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
+                    android.hardware.radio.V1_5.IRadio radioProxy15 =
+                            (android.hardware.radio.V1_5.IRadio) radioProxy;
+                    if (RILJ_LOGD) {
+                        riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                                + " operatorNumeric = " + operatorNumeric
+                                + ", ran = " + accessNetwork);
+                    }
+                    radioProxy15.setNetworkSelectionModeManual_1_5(rr.mSerial,
+                            convertNullToEmptyString(operatorNumeric), accessNetwork);
+                } else {
+                    if (RILJ_LOGD) {
+                        riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                                + " operatorNumeric = " + operatorNumeric);
+                    }
+                    radioProxy.setNetworkSelectionModeManual(rr.mSerial,
+                            convertNullToEmptyString(operatorNumeric));
+                }
             } catch (RemoteException | RuntimeException e) {
                 handleRadioProxyExceptionForRR(rr, "setNetworkSelectionModeManual", e);
             }
@@ -2077,12 +2176,83 @@
         return rasInHalFormat;
     }
 
+    private android.hardware.radio.V1_5.RadioAccessSpecifier
+            convertRadioAccessSpecifierToRadioHAL_1_5(RadioAccessSpecifier ras) {
+        android.hardware.radio.V1_5.RadioAccessSpecifier rasInHalFormat =
+                new android.hardware.radio.V1_5.RadioAccessSpecifier();
+        rasInHalFormat.radioAccessNetwork = ras.getRadioAccessNetwork();
+        List<Integer> bands = null;
+        switch (ras.getRadioAccessNetwork()) {
+            case AccessNetworkType.GERAN:
+                bands = rasInHalFormat.bands.geranBands();
+                break;
+            case AccessNetworkType.UTRAN:
+                bands = rasInHalFormat.bands.utranBands();
+                break;
+            case AccessNetworkType.EUTRAN:
+                bands = rasInHalFormat.bands.eutranBands();
+                break;
+            case AccessNetworkType.NGRAN:
+                bands = rasInHalFormat.bands.ngranBands();
+                break;
+            default:
+                Log.wtf(RILJ_LOG_TAG, "radioAccessNetwork " + ras.getRadioAccessNetwork()
+                        + " not supported!");
+                return null;
+        }
+
+        if (ras.getBands() != null) {
+            for (int band : ras.getBands()) {
+                bands.add(band);
+            }
+        }
+        if (ras.getChannels() != null) {
+            for (int channel : ras.getChannels()) {
+                rasInHalFormat.channels.add(channel);
+            }
+        }
+
+        return rasInHalFormat;
+    }
+
     @Override
     public void startNetworkScan(NetworkScanRequest nsr, Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
-            if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) {
+            if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
+                android.hardware.radio.V1_5.NetworkScanRequest request =
+                        new android.hardware.radio.V1_5.NetworkScanRequest();
+                request.type = nsr.getScanType();
+                request.interval = nsr.getSearchPeriodicity();
+                request.maxSearchTime = nsr.getMaxSearchTime();
+                request.incrementalResultsPeriodicity = nsr.getIncrementalResultsPeriodicity();
+                request.incrementalResults = nsr.getIncrementalResults();
 
+                for (RadioAccessSpecifier ras : nsr.getSpecifiers()) {
+                    android.hardware.radio.V1_5.RadioAccessSpecifier rasInHalFormat =
+                            convertRadioAccessSpecifierToRadioHAL_1_5(ras);
+                    if (rasInHalFormat == null) {
+                        return;
+                    }
+                    request.specifiers.add(rasInHalFormat);
+                }
+
+                request.mccMncs.addAll(nsr.getPlmns());
+                RILRequest rr = obtainRequest(RIL_REQUEST_START_NETWORK_SCAN, result,
+                        mRILDefaultWorkSource);
+
+                if (RILJ_LOGD) {
+                    riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+                }
+
+                try {
+                    android.hardware.radio.V1_5.IRadio radioProxy15 =
+                            (android.hardware.radio.V1_5.IRadio) radioProxy;
+                    radioProxy15.startNetworkScan_1_5(rr.mSerial, request);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "startNetworkScan", e);
+                }
+            } else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) {
                 android.hardware.radio.V1_2.NetworkScanRequest request =
                         new android.hardware.radio.V1_2.NetworkScanRequest();
                 request.type = nsr.getScanType();
@@ -2528,7 +2698,8 @@
 
             if (RILJ_LOGD) {
                 riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " contents = "
-                        + (Build.IS_DEBUGGABLE ? contents : censoredTerminalResponse(contents)));
+                        + (TelephonyUtils.IS_DEBUGGABLE
+                            ? contents : censoredTerminalResponse(contents)));
             }
 
             try {
@@ -3034,6 +3205,36 @@
     }
 
     @Override
+    public void sendCdmaSMSExpectMore(byte[] pdu, Message result) {
+        if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
+            IRadio radioProxy = getRadioProxy(result);
+            // IRadio V1.5
+            android.hardware.radio.V1_5.IRadio radioProxy15 =
+                    (android.hardware.radio.V1_5.IRadio) radioProxy;
+            if (radioProxy15 != null) {
+                RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE, result,
+                    mRILDefaultWorkSource);
+
+                // Do not log function arg for privacy
+                if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+                CdmaSmsMessage msg = new CdmaSmsMessage();
+                constructCdmaSendSmsRilRequest(msg, pdu);
+
+                try {
+                    radioProxy15.sendCdmaSmsExpectMore(rr.mSerial, msg);
+                    mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA,
+                        SmsSession.Event.Format.SMS_FORMAT_3GPP2);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "sendCdmaSMSExpectMore", e);
+                }
+            }
+        } else {
+            sendCdmaSms(pdu, result);
+        }
+    }
+
+    @Override
     public void sendCdmaSms(byte[] pdu, Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
@@ -3510,7 +3711,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;
@@ -3626,7 +3833,7 @@
                     mRILDefaultWorkSource);
 
             if (RILJ_LOGD) {
-                if (Build.IS_DEBUGGABLE) {
+                if (TelephonyUtils.IS_DEBUGGABLE) {
                     riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
                             + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction)
                             + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3)
@@ -3653,7 +3860,7 @@
                     mRILDefaultWorkSource);
 
             if (RILJ_LOGD) {
-                if (Build.IS_DEBUGGABLE) {
+                if (TelephonyUtils.IS_DEBUGGABLE) {
                     riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " aid = " + aid
                             + " p2 = " + p2);
                 } else {
@@ -3704,7 +3911,7 @@
                     mRILDefaultWorkSource);
 
             if (RILJ_LOGD) {
-                if (Build.IS_DEBUGGABLE) {
+                if (TelephonyUtils.IS_DEBUGGABLE) {
                     riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
                             + String.format(" channel = %d", channel)
                             + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction)
@@ -3913,7 +4120,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;
@@ -4355,8 +4584,8 @@
     }
 
     @Override
-    public void setSignalStrengthReportingCriteria(int hysteresisMs, int hysteresisDb,
-            int[] thresholdsDbm, int ran, Message result) {
+    public void setSignalStrengthReportingCriteria(SignalThresholdInfo signalThresholdInfo,
+            int ran, Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
             if (mRadioVersion.less(RADIO_HAL_VERSION_1_2)) {
@@ -4364,26 +4593,58 @@
                         + "than 1.2");
                 return;
             }
-
-            RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA,
-                    result, mRILDefaultWorkSource);
-
-            if (RILJ_LOGD) {
-                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-            }
-
-            try {
-                android.hardware.radio.V1_2.IRadio radioProxy12 =
+            if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)
+                    && mRadioVersion.less(RADIO_HAL_VERSION_1_5)) {
+                RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA,
+                        result, mRILDefaultWorkSource);
+                if (RILJ_LOGD) {
+                    riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+                }
+                try {
+                    android.hardware.radio.V1_2.IRadio radioProxy12 =
                         (android.hardware.radio.V1_2.IRadio) radioProxy;
-                radioProxy12.setSignalStrengthReportingCriteria(rr.mSerial, hysteresisMs,
-                        hysteresisDb, primitiveArrayToArrayList(thresholdsDbm),
-                        convertRanToHalRan(ran));
-            } catch (RemoteException | RuntimeException e) {
-                handleRadioProxyExceptionForRR(rr, "setSignalStrengthReportingCriteria", e);
+                    radioProxy12.setSignalStrengthReportingCriteria(rr.mSerial,
+                            signalThresholdInfo.getHysteresisMs(),
+                            signalThresholdInfo.getHysteresisDb(),
+                            primitiveArrayToArrayList(signalThresholdInfo.getThresholds()),
+                            convertRanToHalRan(ran));
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setSignalStrengthReportingCriteria", e);
+                }
+            }
+            if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
+                RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA,
+                        result, mRILDefaultWorkSource);
+                if (RILJ_LOGD) {
+                    riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+                }
+                try {
+                    android.hardware.radio.V1_5.IRadio radioProxy15 =
+                            (android.hardware.radio.V1_5.IRadio) radioProxy;
+                    radioProxy15.setSignalStrengthReportingCriteria_1_5(rr.mSerial,
+                            convertToHalSignalThresholdInfo(signalThresholdInfo),
+                            convertRanToHalRan(ran));
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(
+                            rr, "setSignalStrengthReportingCriteria_1_5", e);
+                }
             }
         }
     }
 
+    private static android.hardware.radio.V1_5.SignalThresholdInfo convertToHalSignalThresholdInfo(
+            SignalThresholdInfo signalThresholdInfo) {
+        android.hardware.radio.V1_5.SignalThresholdInfo signalThresholdInfoHal =
+                new android.hardware.radio.V1_5.SignalThresholdInfo();
+        signalThresholdInfoHal.signalMeasurement = signalThresholdInfo.getSignalMeasurement();
+        signalThresholdInfoHal.hysteresisMs = signalThresholdInfo.getHysteresisMs();
+        signalThresholdInfoHal.hysteresisDb = signalThresholdInfo.getHysteresisDb();
+        signalThresholdInfoHal.thresholds = primitiveArrayToArrayList(
+                signalThresholdInfo.getThresholds());
+        signalThresholdInfoHal.isEnabled = signalThresholdInfo.isEnabled();
+        return signalThresholdInfoHal;
+    }
+
     @Override
     public void setLinkCapacityReportingCriteria(int hysteresisMs, int hysteresisDlKbps,
             int hysteresisUlKbps, int[] thresholdsDlKbps, int[] thresholdsUlKbps, int ran,
@@ -4428,12 +4689,31 @@
                 return AccessNetwork.CDMA2000;
             case AccessNetworkType.IWLAN:
                 return AccessNetwork.IWLAN;
+            case AccessNetworkType.NGRAN:
+                return AccessNetwork.NGRAN;
             case AccessNetworkType.UNKNOWN:
             default:
                 return 0;
         }
     }
 
+    private static int convertRanToAnt(int radioAccessNetwork) {
+        switch(radioAccessNetwork) {
+            case RadioAccessNetworks.GERAN:
+                return AccessNetworkType.GERAN;
+            case RadioAccessNetworks.UTRAN:
+                return AccessNetworkType.UTRAN;
+            case RadioAccessNetworks.EUTRAN:
+                return AccessNetworkType.EUTRAN;
+            case RadioAccessNetworks.NGRAN:
+                return AccessNetworkType.NGRAN;
+            case RadioAccessNetworks.CDMA2000:
+                return AccessNetworkType.CDMA2000;
+            default:
+                return AccessNetworkType.UNKNOWN;
+        }
+    }
+
     @Override
     public void setSimCardPower(int state, Message result, WorkSource workSource) {
         workSource = getDeafultWorkSourceIfInvalid(workSource);
@@ -4639,6 +4919,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.
      */
@@ -5560,6 +5932,12 @@
                 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";
+            case RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE:
+                return "RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE";
             default: return "<unknown request>";
         }
     }
@@ -5671,6 +6049,12 @@
                 return "RIL_UNSOL_KEEPALIVE_STATUS";
             case RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG:
                 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";
+            case RIL_UNSOL_REGISTRATION_FAILED:
+                return "RIL_UNSOL_REGISTRATION_FAILED";
             default:
                 return "<unknown response>";
         }
@@ -5971,7 +6355,7 @@
     }
 
     /**
-     * Convert SetupDataCallResult defined in 1.0 or 1.4/types.hal into DataCallResponse
+     * Convert SetupDataCallResult defined in 1.0, 1.4, or 1.5 types.hal into DataCallResponse
      * @param dcResult setup data call result
      * @return converted DataCallResponse object
      */
@@ -5979,13 +6363,17 @@
     public static DataCallResponse convertDataCallResult(Object dcResult) {
         if (dcResult == null) return null;
 
-        int cause, suggestedRetryTime, cid, active, mtu;
+        int cause, suggestedRetryTime, cid, active, mtu, mtuV4, mtuV6;
         String ifname;
         int protocolType;
         String[] addresses = null;
         String[] dnses = null;
         String[] gateways = null;
         String[] pcscfs = null;
+
+        List<LinkAddress> laList = new ArrayList<>();
+        int version;
+
         if (dcResult instanceof android.hardware.radio.V1_0.SetupDataCallResult) {
             final android.hardware.radio.V1_0.SetupDataCallResult result =
                     (android.hardware.radio.V1_0.SetupDataCallResult) dcResult;
@@ -6008,6 +6396,8 @@
                 pcscfs = result.pcscf.split("\\s+");
             }
             mtu = result.mtu;
+            mtuV4 = mtuV6 = 0;
+            version = 0;
         } else if (dcResult instanceof android.hardware.radio.V1_4.SetupDataCallResult) {
             final android.hardware.radio.V1_4.SetupDataCallResult result =
                     (android.hardware.radio.V1_4.SetupDataCallResult) dcResult;
@@ -6022,32 +6412,55 @@
             gateways = result.gateways.stream().toArray(String[]::new);
             pcscfs = result.pcscf.stream().toArray(String[]::new);
             mtu = result.mtu;
+            mtuV4 = mtuV6 = 0;
+            version = 4;
+        } else if (dcResult instanceof android.hardware.radio.V1_5.SetupDataCallResult) {
+            final android.hardware.radio.V1_5.SetupDataCallResult result =
+                    (android.hardware.radio.V1_5.SetupDataCallResult) dcResult;
+            cause = result.cause;
+            suggestedRetryTime = result.suggestedRetryTime;
+            cid = result.cid;
+            active = result.active;
+            protocolType = result.type;
+            ifname = result.ifname;
+            laList = result.addresses.stream().map(a -> new LinkAddress(
+                    InetAddresses.parseNumericAddress(a.address), 0, a.properties, 0,
+                    a.deprecationTime, a.expirationTime)).collect(Collectors.toList());
+
+            dnses = result.dnses.stream().toArray(String[]::new);
+            gateways = result.gateways.stream().toArray(String[]::new);
+            pcscfs = result.pcscf.stream().toArray(String[]::new);
+            mtu = 0;
+            mtuV4 = result.mtuV4;
+            mtuV6 = result.mtuV6;
+            version = 5;
         } else {
             Rlog.e(RILJ_LOG_TAG, "Unsupported SetupDataCallResult " + dcResult);
             return null;
         }
 
-        // Process address
-        List<LinkAddress> laList = new ArrayList<>();
-        if (addresses != null) {
-            for (String address : addresses) {
-                address = address.trim();
-                if (address.isEmpty()) continue;
+        if (version < 5) {
+            // Process address
+            if (addresses != null) {
+                for (String address : addresses) {
+                    address = address.trim();
+                    if (address.isEmpty()) continue;
 
-                try {
-                    LinkAddress la;
-                    // Check if the address contains prefix length. If yes, LinkAddress
-                    // can parse that.
-                    if (address.split("/").length == 2) {
-                        la = new LinkAddress(address);
-                    } else {
-                        InetAddress ia = NetworkUtils.numericToInetAddress(address);
-                        la = new LinkAddress(ia, (ia instanceof Inet4Address) ? 32 : 128);
+                    try {
+                        LinkAddress la;
+                        // Check if the address contains prefix length. If yes, LinkAddress
+                        // can parse that.
+                        if (address.split("/").length == 2) {
+                            la = new LinkAddress(address);
+                        } else {
+                            InetAddress ia = InetAddresses.parseNumericAddress(address);
+                            la = new LinkAddress(ia, (ia instanceof Inet4Address) ? 32 : 128);
+                        }
+
+                        laList.add(la);
+                    } catch (IllegalArgumentException e) {
+                        Rlog.e(RILJ_LOG_TAG, "Unknown address: " + address, e);
                     }
-
-                    laList.add(la);
-                } catch (IllegalArgumentException e) {
-                    Rlog.e(RILJ_LOG_TAG, "Unknown address: " + address, e);
                 }
             }
         }
@@ -6059,7 +6472,7 @@
                 dns = dns.trim();
                 InetAddress ia;
                 try {
-                    ia = NetworkUtils.numericToInetAddress(dns);
+                    ia = InetAddresses.parseNumericAddress(dns);
                     dnsList.add(ia);
                 } catch (IllegalArgumentException e) {
                     Rlog.e(RILJ_LOG_TAG, "Unknown dns: " + dns, e);
@@ -6074,7 +6487,7 @@
                 gateway = gateway.trim();
                 InetAddress ia;
                 try {
-                    ia = NetworkUtils.numericToInetAddress(gateway);
+                    ia = InetAddresses.parseNumericAddress(gateway);
                     gatewayList.add(ia);
                 } catch (IllegalArgumentException e) {
                     Rlog.e(RILJ_LOG_TAG, "Unknown gateway: " + gateway, e);
@@ -6089,7 +6502,7 @@
                 pcscf = pcscf.trim();
                 InetAddress ia;
                 try {
-                    ia = NetworkUtils.numericToInetAddress(pcscf);
+                    ia = InetAddresses.parseNumericAddress(pcscf);
                     pcscfList.add(ia);
                 } catch (IllegalArgumentException e) {
                     Rlog.e(RILJ_LOG_TAG, "Unknown pcscf: " + pcscf, e);
@@ -6097,8 +6510,22 @@
             }
         }
 
-        return new DataCallResponse(cause, suggestedRetryTime, cid, active, protocolType, ifname,
-                laList, dnsList, gatewayList, pcscfList, mtu);
+        return new DataCallResponse.Builder()
+                .setCause(cause)
+                .setSuggestedRetryTime(suggestedRetryTime)
+                .setId(cid)
+                .setLinkStatus(active)
+                .setProtocolType(protocolType)
+                .setInterfaceName(ifname)
+                .setAddresses(laList)
+                .setDnsAddresses(dnsList)
+                .setGatewayAddresses(gatewayList)
+                .setPcscfAddresses(pcscfList)
+                .setMtu(mtu)
+                .setMtuV4(mtuV4)
+                .setMtuV6(mtuV6)
+                .setVersion(version)
+                .build();
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/RILRequest.java b/src/java/com/android/internal/telephony/RILRequest.java
index 2d8f952..0d5f8e7 100644
--- a/src/java/com/android/internal/telephony/RILRequest.java
+++ b/src/java/com/android/internal/telephony/RILRequest.java
@@ -16,13 +16,14 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemClock;
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Random;
@@ -148,7 +149,7 @@
         final ArrayList<WorkChain> workChains = mWorkSource.getWorkChains();
         if (workChains != null && !workChains.isEmpty()) {
             final WorkChain workChain = workChains.get(0);
-            return workChain.getAttributionUid() + ":" + workChain.getTags()[0];
+            return workChain.toString();
         }
 
         return null;
diff --git a/src/java/com/android/internal/telephony/RadioCapability.java b/src/java/com/android/internal/telephony/RadioCapability.java
index 2b2615b..3475201 100644
--- a/src/java/com/android/internal/telephony/RadioCapability.java
+++ b/src/java/com/android/internal/telephony/RadioCapability.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.telephony.TelephonyManager;
 
 /**
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index a2d4e5b..24a7791 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -38,15 +38,19 @@
 import android.os.Registrant;
 import android.os.RemoteException;
 import android.os.WorkSource;
-import android.telephony.Rlog;
+import android.telephony.PhoneCapability;
+import android.telephony.SimSlotCapability;
 import android.util.SparseArray;
 
 import com.android.internal.telephony.uicc.IccSlotStatus;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 
 /**
  * This class provides wrapper APIs for IRadioConfig interface.
@@ -64,6 +68,8 @@
 
     private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_1 = new HalVersion(1, 1);
 
+    private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_3 = new HalVersion(1, 3);
+
     private final boolean mIsMobileNetworkSupported;
     private volatile IRadioConfig mRadioConfigProxy = null;
     // IRadioConfig version
@@ -340,11 +346,20 @@
             logd(rr.serialString() + "> " + requestToString(rr.mRequest));
         }
 
-        try {
-            ((android.hardware.radio.config.V1_1.IRadioConfig) mRadioConfigProxy)
-                    .getPhoneCapability(rr.mSerial);
-        } catch (RemoteException | RuntimeException e) {
-            resetProxyAndRequestList("getPhoneCapability", e);
+        if (mRadioConfigVersion.greaterOrEqual(RADIO_CONFIG_HAL_VERSION_1_3)) {
+            try {
+                ((android.hardware.radio.config.V1_3.IRadioConfig) mRadioConfigProxy)
+                        .getPhoneCapability_1_3(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                resetProxyAndRequestList("getPhoneCapability_1_3", e);
+            }
+        } else {
+            try {
+                ((android.hardware.radio.config.V1_1.IRadioConfig) mRadioConfigProxy)
+                        .getPhoneCapability(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                resetProxyAndRequestList("getPhoneCapability", e);
+            }
         }
     }
 
@@ -487,6 +502,49 @@
         return response;
     }
 
+    static PhoneCapability convertHalPhoneCapability(
+            android.hardware.radio.config.V1_1.PhoneCapability pc) {
+        long psDataConnectionLingerTimeMillis = pc.isInternetLingeringSupported ? 1 : 0;
+
+        List<String> logicalModemUuids = new ArrayList<>();
+        for (android.hardware.radio.config.V1_1.ModemInfo modemInfo : pc.logicalModemList) {
+            logicalModemUuids.add("com.xxxx.lm" + modemInfo.modemId);
+        }
+
+        List<List<Long>> features = new ArrayList<>();
+        for (int i = 0; i < pc.maxActiveData; i++) {
+            List<Long> feature = new ArrayList<>();
+            feature.add(PhoneCapability.MODEM_FEATURE_PS_VOICE_REG);
+            features.add(feature);
+        }
+
+        return new PhoneCapability(0, 0, 0, 0, psDataConnectionLingerTimeMillis, 0,
+                null, null, null, null, logicalModemUuids, null, features);
+    }
+
+    static PhoneCapability convertHalPhoneCapability_1_3(
+            android.hardware.radio.config.V1_3.PhoneCapability pc) {
+        List<SimSlotCapability> simSlotCapabilities = new ArrayList<>();
+        for (android.hardware.radio.config.V1_3.SimSlotCapability sc : pc.simSlotCapabilities) {
+            simSlotCapabilities.add(new SimSlotCapability(sc.physicalSlotId, sc.slotType));
+        }
+
+        List<List<Long>> features = new ArrayList<>();
+        for (android.hardware.radio.config.V1_3.ConcurrentModemFeatures cmf
+                : pc.concurrentFeatureSupport) {
+            features.add(cmf.modemFeatures
+                    .stream()
+                    .mapToLong(Integer::longValue)
+                    .boxed()
+                    .collect(Collectors.toList()));
+        }
+
+        return new PhoneCapability(pc.utranUeCategoryDl, pc.utranUeCategoryUl,
+                pc.eutranUeCategoryDl, pc.eutranUeCategoryUl, pc.psDataConnectionLingerTimeMillis,
+                pc.supportedRats, pc.geranBands, pc.utranBands, pc.eutranBands, pc.ngranBands,
+                pc.logicalModemUuids, simSlotCapabilities, features);
+    }
+
     private static void logd(String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/RadioConfigIndication.java b/src/java/com/android/internal/telephony/RadioConfigIndication.java
index 39af57b..639272c 100644
--- a/src/java/com/android/internal/telephony/RadioConfigIndication.java
+++ b/src/java/com/android/internal/telephony/RadioConfigIndication.java
@@ -18,9 +18,9 @@
 
 import android.hardware.radio.config.V1_2.IRadioConfigIndication;
 import android.os.AsyncResult;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.uicc.IccSlotStatus;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 
diff --git a/src/java/com/android/internal/telephony/RadioConfigResponse.java b/src/java/com/android/internal/telephony/RadioConfigResponse.java
index 475f866..0f4a719 100644
--- a/src/java/com/android/internal/telephony/RadioConfigResponse.java
+++ b/src/java/com/android/internal/telephony/RadioConfigResponse.java
@@ -20,14 +20,12 @@
 import android.hardware.radio.V1_0.RadioResponseInfo;
 import android.hardware.radio.config.V1_1.ModemsConfig;
 import android.hardware.radio.config.V1_2.IRadioConfigResponse;
-import android.telephony.ModemInfo;
 import android.telephony.PhoneCapability;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.uicc.IccSlotStatus;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * This class is the implementation of IRadioConfigResponse interface.
@@ -115,23 +113,6 @@
         }
     }
 
-    private PhoneCapability convertHalPhoneCapability(
-            android.hardware.radio.config.V1_1.PhoneCapability phoneCapability) {
-        // TODO b/121394331: clean up V1_1.PhoneCapability fields.
-        int maxActiveVoiceCalls = 0;
-        int maxActiveData = phoneCapability.maxActiveData;
-        int max5G = 0;
-        boolean validationBeforeSwitchSupported = phoneCapability.isInternetLingeringSupported;
-        List<ModemInfo> logicalModemList = new ArrayList();
-
-        for (android.hardware.radio.config.V1_1.ModemInfo
-                modemInfo : phoneCapability.logicalModemList) {
-            logicalModemList.add(new ModemInfo(modemInfo.modemId));
-        }
-
-        return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList,
-                validationBeforeSwitchSupported);
-    }
     /**
      * Response function for IRadioConfig.getPhoneCapability().
      */
@@ -140,7 +121,7 @@
         RILRequest rr = mRadioConfig.processResponse(responseInfo);
 
         if (rr != null) {
-            PhoneCapability ret = convertHalPhoneCapability(phoneCapability);
+            PhoneCapability ret = RadioConfig.convertHalPhoneCapability(phoneCapability);
             if (responseInfo.error == RadioError.NONE) {
                 // send response
                 RadioResponse.sendMessageResponse(rr.mResult, ret);
@@ -158,6 +139,31 @@
     }
 
     /**
+     * Response function for IRadioConfig.getPhoneCapability_1_3().
+     */
+    public void getPhoneCapabilityResponse_1_3(RadioResponseInfo responseInfo,
+            android.hardware.radio.config.V1_3.PhoneCapability phoneCapability) {
+        RILRequest rr = mRadioConfig.processResponse(responseInfo);
+
+        if (rr != null) {
+            PhoneCapability ret = RadioConfig.convertHalPhoneCapability_1_3(phoneCapability);
+            if (responseInfo.error == RadioError.NONE) {
+                // send response
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+                Rlog.d(TAG, rr.serialString() + "< "
+                        + mRadioConfig.requestToString(rr.mRequest) + " " + ret.toString());
+            } else {
+                rr.onError(responseInfo.error, ret);
+                Rlog.e(TAG, rr.serialString() + "< "
+                        + mRadioConfig.requestToString(rr.mRequest) + " error "
+                        + responseInfo.error);
+            }
+        } else {
+            Rlog.e(TAG, "getPhoneCapabilityResponse_1_3: Error " + responseInfo.toString());
+        }
+    }
+
+    /**
      * Response function for IRadioConfig.setPreferredDataModem().
      */
     public void setPreferredDataModemResponse(RadioResponseInfo responseInfo) {
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index 5d00690..ede5854 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;
@@ -84,11 +85,12 @@
 import android.hardware.radio.V1_0.SuppSvcNotification;
 import android.hardware.radio.V1_2.CellConnectionStatus;
 import android.hardware.radio.V1_4.IRadioIndication;
-import android.hardware.radio.V1_4.RadioFrequencyInfo.hidl_discriminator;
 import android.os.AsyncResult;
-import android.os.SystemProperties;
+import android.sysprop.TelephonyProperties;
 import android.telephony.Annotation.RadioPowerState;
+import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PcoData;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.ServiceState;
@@ -211,8 +213,7 @@
         result[0] = nitzTime;
         result[1] = receivedTime;
 
-        boolean ignoreNitz = SystemProperties.getBoolean(
-                TelephonyProperties.PROPERTY_IGNORE_NITZ, false);
+        boolean ignoreNitz = TelephonyProperties.ignore_nitz().orElse(false);
 
         if (ignoreNitz) {
             if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
@@ -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) {
@@ -962,6 +974,32 @@
     }
 
     /**
+     * Indicate that a registration failure has occurred.
+     *
+     * @param cellIdentity a CellIdentity the CellIdentity of the Cell
+     * @param chosenPlmn a 5 or 6 digit alphanumeric string indicating the PLMN on which
+     *        registration failed
+     * @param domain the domain of the failed procedure: CS, PS, or both
+     * @param causeCode the primary failure cause code of the procedure
+     * @param additionalCauseCode an additional cause code if applicable
+     */
+    public void registrationFailed(int indicationType,
+            android.hardware.radio.V1_5.CellIdentity cellIdentity, String chosenPlmn,
+            @NetworkRegistrationInfo.Domain int domain,
+            int causeCode, int additionalCauseCode) {
+        mRil.processIndication(indicationType);
+
+        CellIdentity ci = CellIdentity.create(cellIdentity);
+
+        mRil.mRegistrationFailedRegistrant.notifyRegistrant(
+                new AsyncResult(
+                        null,
+                        new RegistrationFailedEvent(ci, chosenPlmn, domain,
+                                causeCode, additionalCauseCode),
+                        null));
+    }
+
+    /**
      * @param stateInt
      * @return {@link RadioPowerState RadioPowerState}
      */
@@ -995,10 +1033,10 @@
             android.hardware.radio.V1_4.PhysicalChannelConfig config) {
 
         switch (config.rfInfo.getDiscriminator()) {
-            case hidl_discriminator.range:
+            case android.hardware.radio.V1_4.RadioFrequencyInfo.hidl_discriminator.range:
                 builder.setFrequencyRange(config.rfInfo.range());
                 break;
-            case hidl_discriminator.channelNumber:
+            case android.hardware.radio.V1_4.RadioFrequencyInfo.hidl_discriminator.channelNumber:
                 builder.setChannelNumber(config.rfInfo.channelNumber());
                 break;
             default:
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index a36b7a6..a5eab2c 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -919,6 +919,15 @@
     }
 
     /**
+     *
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param sms Sms result struct as defined by SendSmsResult in types.hal
+     */
+    public void sendCdmaSMSExpectMoreResponse(RadioResponseInfo responseInfo, SendSmsResult sms) {
+        responseSms(responseInfo, sms);
+    }
+
+    /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void acknowledgeLastIncomingCdmaSmsResponse(RadioResponseInfo responseInfo) {
@@ -1452,6 +1461,13 @@
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
+    public void setSignalStrengthReportingCriteriaResponse_1_5(RadioResponseInfo responseInfo) {
+        responseVoid(responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
     public void setLinkCapacityReportingCriteriaResponse(RadioResponseInfo responseInfo) {
         responseVoid(responseInfo);
     }
@@ -2186,10 +2202,10 @@
                 }
                 final int rxModeTimeMs = activityInfo.rxModeTimeMs;
                 ret = new ModemActivityInfo(SystemClock.elapsedRealtime(), sleepModeTimeMs,
-                        idleModeTimeMs, txModeTimeMs, rxModeTimeMs, 0);
+                        idleModeTimeMs, txModeTimeMs, rxModeTimeMs);
             } else {
                 ret = new ModemActivityInfo(0, 0, 0, new int [ModemActivityInfo.TX_POWER_LEVELS],
-                        0, 0);
+                        0);
                 responseInfo.error = RadioError.NONE;
             }
             sendMessageResponse(rr.mResult, ret);
@@ -2356,4 +2372,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/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java
index 7b45c53..084223f 100644
--- a/src/java/com/android/internal/telephony/RatRatcheter.java
+++ b/src/java/com/android/internal/telephony/RatRatcheter.java
@@ -20,17 +20,19 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.NetworkRegistrationInfo;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import com.android.telephony.Rlog;
+
 import java.util.Arrays;
 
 /**
@@ -83,8 +85,14 @@
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
-        phone.getContext().registerReceiverAsUser(mConfigChangedReceiver, UserHandle.ALL,
-                intentFilter, null, null);
+        try {
+            Context contextAsUser = phone.getContext().createPackageContextAsUser(
+                phone.getContext().getPackageName(), 0, UserHandle.ALL);
+            contextAsUser.registerReceiver(mConfigChangedReceiver,
+                intentFilter, null /* broadcastPermission */, null);
+        } catch (PackageManager.NameNotFoundException e) {
+            Rlog.e(LOG_TAG, "Package name not found: " + e.getMessage());
+        }
         resetRatFamilyMap();
     }
 
diff --git a/src/java/com/android/internal/telephony/RegistrationFailedEvent.java b/src/java/com/android/internal/telephony/RegistrationFailedEvent.java
new file mode 100644
index 0000000..35807ca
--- /dev/null
+++ b/src/java/com/android/internal/telephony/RegistrationFailedEvent.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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 android.annotation.NonNull;
+import android.telephony.CellIdentity;
+import android.telephony.NetworkRegistrationInfo;
+
+/**
+ * Event fired to notify of a registration failure.
+ */
+public class RegistrationFailedEvent {
+    /** The Cell Identity of the cell on which registration failed */
+    public final CellIdentity cellIdentity;
+
+    /** The PLMN for that cell on which registration failed */
+    public final String chosenPlmn;
+
+    /** The registration domain(s) for this registration attempt */
+    @NetworkRegistrationInfo.Domain public final int domain;
+
+    /** The registration cause code */
+    public final int causeCode;
+
+    /** The additional cause code in case of a combined procedure */
+    public final int additionalCauseCode;
+
+    /** Constructor for this event */
+    public RegistrationFailedEvent(@NonNull CellIdentity cellIdentity,
+            @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) {
+        this.cellIdentity = cellIdentity;
+        this.chosenPlmn = chosenPlmn;
+        this.domain = domain;
+        this.causeCode = causeCode;
+        this.additionalCauseCode = additionalCauseCode;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("{CellIdentity=")
+                .append(cellIdentity)
+                .append(", chosenPlmn=")
+                .append(chosenPlmn)
+                .append(", domain=")
+                .append(domain)
+                .append(", causeCode=")
+                .append(causeCode)
+                .append(", additionalCauseCode=")
+                .append(additionalCauseCode)
+                .toString();
+    }
+}
diff --git a/src/java/com/android/internal/telephony/RetryManager.java b/src/java/com/android/internal/telephony/RetryManager.java
index 87d6cf5..62cde52 100644
--- a/src/java/com/android/internal/telephony/RetryManager.java
+++ b/src/java/com/android/internal/telephony/RetryManager.java
@@ -16,17 +16,18 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.os.Build;
 import android.os.PersistableBundle;
 import android.os.SystemProperties;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
 import android.util.Pair;
 
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
+
 import java.util.ArrayList;
 import java.util.Random;
 
@@ -332,7 +333,7 @@
         String otherConfigString = null;
 
         try {
-            if (Build.IS_DEBUGGABLE) {
+            if (TelephonyUtils.IS_DEBUGGABLE) {
                 // Using system properties is easier for testing from command line.
                 String config = SystemProperties.get("test.data_retry_config");
                 if (!TextUtils.isEmpty(config)) {
diff --git a/src/java/com/android/internal/telephony/RilWakelockInfo.java b/src/java/com/android/internal/telephony/RilWakelockInfo.java
index 5d9e54b..a5aea58 100644
--- a/src/java/com/android/internal/telephony/RilWakelockInfo.java
+++ b/src/java/com/android/internal/telephony/RilWakelockInfo.java
@@ -17,10 +17,10 @@
 package com.android.internal.telephony;
 
 import android.annotation.TargetApi;
-import android.os.Build;
-import android.telephony.Rlog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 @TargetApi(8)
 public class RilWakelockInfo {
@@ -57,7 +57,7 @@
 
     private int validateConcurrentRequests(int concurrentRequests) {
         if(concurrentRequests <= 0) {
-            if(Build.IS_DEBUGGABLE) {
+            if (TelephonyUtils.IS_DEBUGGABLE) {
                 IllegalArgumentException e = new IllegalArgumentException(
                     "concurrentRequests should always be greater than 0.");
                 Rlog.e(LOG_TAG, e.toString());
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index 0f3d8aa..7ab55a1 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -30,13 +30,12 @@
 import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
 
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -64,7 +63,6 @@
 import android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
@@ -87,6 +85,7 @@
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccController;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -383,13 +382,6 @@
         }
     }
 
-    private static int getSendSmsFlag(@Nullable PendingIntent deliveryIntent) {
-        if (deliveryIntent == null) {
-            return 0;
-        }
-        return CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS;
-    }
-
     /**
      * Use the carrier messaging service to send a text SMS.
      */
@@ -405,8 +397,13 @@
 
             if (text != null) {
                 try {
-                    sendTextSms(text, getSubId(),
-                            mTracker.mDestAddress, getSendSmsFlag(mTracker.mDeliveryIntent),
+                    sendTextSms(
+                            text,
+                            getSubId(),
+                            mTracker.mDestAddress,
+                            (mTracker.mDeliveryIntent != null)
+                                    ? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
+                                    : 0,
                             mSenderCallback);
                 } catch (RuntimeException e) {
                     Rlog.e(TAG, "Exception sending the SMS: " + e);
@@ -438,9 +435,15 @@
 
             if (data != null) {
                 try {
-                    sendDataSms(data, getSubId(),
-                            mTracker.mDestAddress, destPort,
-                            getSendSmsFlag(mTracker.mDeliveryIntent), mSenderCallback);
+                    sendDataSms(
+                            data,
+                            getSubId(),
+                            mTracker.mDestAddress,
+                            destPort,
+                            (mTracker.mDeliveryIntent != null)
+                                    ? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
+                                    : 0,
+                            mSenderCallback);
                 } catch (RuntimeException e) {
                     Rlog.e(TAG, "Exception sending the SMS: " + e);
                     mSenderCallback.onSendSmsComplete(
@@ -566,10 +569,23 @@
 
         @Override
         public void onServiceReady() {
+            boolean statusReportRequested = false;
+            for (SmsTracker tracker : mTrackers) {
+                if (tracker.mDeliveryIntent != null) {
+                    statusReportRequested = true;
+                    break;
+                }
+            }
+
             try {
                 sendMultipartTextSms(
-                        mParts, getSubId(), mTrackers[0].mDestAddress,
-                        getSendSmsFlag(mTrackers[0].mDeliveryIntent), mSenderCallback);
+                        mParts,
+                        getSubId(),
+                        mTrackers[0].mDestAddress,
+                        statusReportRequested
+                                ? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
+                                : 0,
+                        mSenderCallback);
             } catch (RuntimeException e) {
                 Rlog.e(TAG, "Exception sending the SMS: " + e);
                 mSenderCallback.onSendMultipartSmsComplete(
@@ -1223,15 +1239,15 @@
             }
 
             if (error == RESULT_ERROR_NONE) {
-                PackageManager pm = mContext.getPackageManager();
+                UserHandle userHandle = UserHandle.of(trackers[0].mUserId);
+                PackageManager pm = mContext.createContextAsUser(userHandle, 0).getPackageManager();
 
                 try {
                     // Get package info via packagemanager
                     appInfo =
-                            pm.getPackageInfoAsUser(
+                            pm.getPackageInfo(
                                     trackers[0].getAppPackageName(),
-                                    PackageManager.GET_SIGNATURES,
-                                    trackers[0].mUserId);
+                                    PackageManager.GET_SIGNATURES);
                 } catch (PackageManager.NameNotFoundException e) {
                     Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
                     error = RESULT_ERROR_GENERIC_FAILURE;
@@ -1824,15 +1840,14 @@
             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
             SmsHeader smsHeader, boolean expectMore, String fullMessageText, boolean isText,
             boolean persistMessage, int priority, int validityPeriod, boolean isForVvm) {
-        // Get calling app package name via UID from Binder call
-        PackageManager pm = mContext.getPackageManager();
 
         // Get package info via packagemanager
-        final int userId = UserHandle.getUserHandleForUid(Binder.getCallingUid()).getIdentifier();
+        UserHandle callingUser = UserHandle.getUserHandleForUid(Binder.getCallingUid());
+        final int userId = callingUser.getIdentifier();
+        PackageManager pm = mContext.createContextAsUser(callingUser, 0).getPackageManager();
         PackageInfo appInfo = null;
         try {
-            appInfo = pm.getPackageInfoAsUser(
-                    callingPackage, PackageManager.GET_SIGNATURES, userId);
+            appInfo = pm.getPackageInfo(callingPackage, PackageManager.GET_SIGNATURES);
         } catch (PackageManager.NameNotFoundException e) {
             // error will be logged in sendRawPdu
         }
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 30391ca..b8b4a8c 100755
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony;
 
-import static android.provider.Telephony.ServiceStateTable.getContentValuesForServiceState;
 import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
 
 import static com.android.internal.telephony.CarrierActionAgent.CARRIER_ACTION_SET_RADIO_ENABLED;
@@ -26,13 +25,14 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -42,18 +42,20 @@
 import android.net.NetworkCapabilities;
 import android.os.AsyncResult;
 import android.os.BaseBundle;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.TimestampedValue;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
+import android.sysprop.TelephonyProperties;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
@@ -65,21 +67,20 @@
 import android.telephony.CellIdentityTdscdma;
 import android.telephony.CellIdentityWcdma;
 import android.telephony.CellInfo;
-import android.telephony.CellLocation;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.CellSignalStrengthNr;
 import android.telephony.DataSpecificRegistrationInfo;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PhysicalChannelConfig;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.ServiceState.RilRadioTechnology;
 import android.telephony.SignalStrength;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.telephony.VoiceSpecificRegistrationInfo;
-import android.telephony.cdma.CdmaCellLocation;
-import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.LocalLog;
@@ -87,7 +88,6 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.StatsLog;
-import android.util.TimestampedValue;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
@@ -108,9 +108,11 @@
 import com.android.internal.telephony.uicc.UiccCardApplication;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UiccProfile;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.telephony.util.NotificationChannelController;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -279,6 +281,16 @@
     protected static final int EVENT_PHYSICAL_CHANNEL_CONFIG           = 55;
     protected static final int EVENT_CELL_LOCATION_RESPONSE            = 56;
     protected static final int EVENT_CARRIER_CONFIG_CHANGED            = 57;
+    private static final int EVENT_POLL_STATE_REQUEST                  = 58;
+
+    /**
+     * The current service state.
+     *
+     * This is a column name in {@link android.provider.Telephony.ServiceStateTable}.
+     *
+     * Copied from packages/services/Telephony/src/com/android/phone/ServiceStateProvider.java
+     */
+    private static final String SERVICE_STATE = "service_state";
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"CARRIER_NAME_DISPLAY_BITMASK"},
@@ -386,9 +398,7 @@
                             com.android.internal.R.bool.skip_restoring_network_selection);
                     mPhone.sendSubscriptionSettings(restoreSelection);
 
-                    mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
-                            ServiceState.rilRadioTechnologyToString(
-                                    mSS.getRilDataRadioTechnology()));
+                    setDataNetworkTypeForPhone(mSS.getRilDataRadioTechnology());
 
                     if (mSpnUpdatePending) {
                         mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), mCurShowPlmn,
@@ -607,8 +617,9 @@
                 .makeEriManager(mPhone, EriManager.ERI_FROM_XML);
 
         mRatRatcheter = new RatRatcheter(mPhone);
-        mVoiceCapable = mPhone.getContext().getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
+        mVoiceCapable = ((TelephonyManager) mPhone.getContext()
+                .getSystemService(Context.TELEPHONY_SERVICE))
+                .isVoiceCapable();
         mUiccController = UiccController.getInstance();
 
         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
@@ -699,7 +710,7 @@
         }
 
         // If we are previously in service, we need to notify that we are out of service now.
-        if (mSS != null && mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+        if (mSS != null && mSS.getState() == ServiceState.STATE_IN_SERVICE) {
             mNetworkDetachedRegistrants.notifyRegistrants();
         }
 
@@ -728,7 +739,8 @@
         mMin = null;
         mPrlVersion = null;
         mIsMinInfoReady = false;
-        mNitzState.handleCountryUnavailable();
+        mLastNitzData = null;
+        mNitzState.handleNetworkUnavailable();
         mCellIdentity = null;
         mNewCellIdentity = null;
         mSignalStrengthUpdatedTime = System.currentTimeMillis();
@@ -765,8 +777,7 @@
         // on fields like mIsSubscriptionFromRuim (which is updated above)
         onUpdateIccAvailability();
 
-        mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
-                ServiceState.rilRadioTechnologyToString(ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN));
+        setDataNetworkTypeForPhone(ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN);
         // Query signal strength from the modem after service tracker is created (i.e. boot up,
         // switching between GSM and CDMA phone), because the unsolicited signal strength
         // information might come late or even never come. This will get the accurate signal
@@ -813,6 +824,10 @@
     }
     public boolean getPowerStateFromCarrier() { return !mRadioDisabledByCarrier; }
 
+    public List<PhysicalChannelConfig> getPhysicalChannelConfigList() {
+        return mLastPhysicalChannelConfigList;
+    }
+
     private SignalStrength mLastSignalStrength = null;
     @UnsupportedAppUsage
     protected boolean notifySignalStrength() {
@@ -837,7 +852,7 @@
      */
     protected void notifyVoiceRegStateRilRadioTechnologyChanged() {
         int rat = mSS.getRilVoiceRadioTechnology();
-        int vrs = mSS.getVoiceRegState();
+        int vrs = mSS.getState();
         if (DBG) log("notifyVoiceRegStateRilRadioTechnologyChanged: vrs=" + vrs + " rat=" + rat);
 
         mVoiceRegStateOrRatChangedRegistrants.notifyResult(new Pair<Integer, Integer>(vrs, rat));
@@ -864,8 +879,7 @@
                 registrantList.notifyResult(new Pair<>(drs, rat));
             }
         }
-        mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
-                ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology()));
+        setDataNetworkTypeForPhone(mSS.getRilDataRadioTechnology());
     }
 
     /**
@@ -876,11 +890,11 @@
     protected void useDataRegStateForDataOnlyDevices() {
         if (mVoiceCapable == false) {
             if (DBG) {
-                log("useDataRegStateForDataOnlyDevice: VoiceRegState=" + mNewSS.getVoiceRegState()
-                    + " DataRegState=" + mNewSS.getDataRegState());
+                log("useDataRegStateForDataOnlyDevice: VoiceRegState=" + mNewSS.getState()
+                        + " DataRegState=" + mNewSS.getDataRegistrationState());
             }
             // TODO: Consider not lying and instead have callers know the difference.
-            mNewSS.setVoiceRegState(mNewSS.getDataRegState());
+            mNewSS.setVoiceRegState(mNewSS.getDataRegistrationState());
         }
     }
 
@@ -889,8 +903,8 @@
         if (mPhone.getContext().getResources().
                 getBoolean(com.android.internal.R.bool.config_switch_phone_on_voice_reg_state_change)) {
             // If the phone is not registered on a network, no need to update.
-            boolean isRegistered = mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE ||
-                    mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY;
+            boolean isRegistered = mSS.getState() == ServiceState.STATE_IN_SERVICE
+                    || mSS.getState() == ServiceState.STATE_EMERGENCY_ONLY;
             if (!isRegistered) {
                 log("updatePhoneObject: Ignore update");
                 return;
@@ -1138,20 +1152,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
@@ -1200,7 +1218,7 @@
                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
                 mPrevSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
                 mIsSimReady = true;
-                pollState();
+                pollStateInternal(false);
                 // Signal strength polling stops when radio is off
                 queueNextSignalStrengthPoll();
                 break;
@@ -1217,11 +1235,11 @@
                 // This will do nothing in the 'radio not available' case
                 setPowerStateToDesired();
                 // These events are modem triggered, so pollState() needs to be forced
-                modemTriggeredPollState();
+                pollStateInternal(true);
                 break;
 
             case EVENT_NETWORK_STATE_CHANGED:
-                modemTriggeredPollState();
+                pollStateInternal(true);
                 break;
 
             case EVENT_GET_SIGNAL_STRENGTH:
@@ -1245,7 +1263,7 @@
                             .getCellIdentity();
                     updateOperatorNameForCellIdentity(cellIdentity);
                     mCellIdentity = cellIdentity;
-                    mPhone.notifyLocationChanged(getCellLocation());
+                    mPhone.notifyLocationChanged(getCellIdentity());
                 }
 
                 // Release any temporary cell lock, which could have been
@@ -1358,7 +1376,7 @@
 
             case EVENT_CHECK_REPORT_GPRS:
                 if (mPhone.isPhoneTypeGsm() && mSS != null &&
-                        !isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
+                        !isGprsConsistent(mSS.getDataRegistrationState(), mSS.getState())) {
 
                     // Can't register data service while voice service is ok
                     // i.e. CREG is ok while CGREG is not
@@ -1427,7 +1445,7 @@
                 if (mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
                     // Subscription will be read from SIM I/O
                     if (DBG) log("Receive EVENT_RUIM_READY");
-                    pollState();
+                    pollStateInternal(false);
                 } else {
                     if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
                     getSubscriptionInfoAndStartPollingThreads();
@@ -1520,7 +1538,7 @@
                         // SID/NID/PRL is loaded. Poll service state
                         // again to update to the roaming state with
                         // the latest variables.
-                        pollState();
+                        pollStateInternal(false);
                     }
                 }
                 break;
@@ -1576,6 +1594,8 @@
                     // Notify NR frequency, NR connection status or bandwidths changed.
                     if (hasChanged) {
                         mPhone.notifyServiceStateChanged(mSS);
+                        TelephonyMetrics.getInstance().writeServiceStateChanged(
+                                mPhone.getPhoneId(), mSS);
                     }
                 }
                 break;
@@ -1583,15 +1603,15 @@
             case EVENT_CELL_LOCATION_RESPONSE:
                 ar = (AsyncResult) msg.obj;
                 if (ar == null) {
-                    loge("Invalid null response to getCellLocation!");
+                    loge("Invalid null response to getCellIdentity!");
                     break;
                 }
                 // This response means that the correct CellInfo is already cached; thus we
                 // can rely on the last cell info to already contain any cell info that is
                 // available, which means that we can return the result of the existing
-                // getCellLocation() function without any additional processing here.
+                // getCellIdentity() function without any additional processing here.
                 Message rspRspMsg = (Message) ar.userObj;
-                AsyncResult.forMessage(rspRspMsg, getCellLocation(), ar.exception);
+                AsyncResult.forMessage(rspRspMsg, getCellIdentity(), ar.exception);
                 rspRspMsg.sendToTarget();
                 break;
 
@@ -1599,6 +1619,10 @@
                 onCarrierConfigChanged();
                 break;
 
+            case EVENT_POLL_STATE_REQUEST:
+                pollStateInternal(false);
+                break;
+
             default:
                 log("Unhandled message with number: " + msg.what);
                 break;
@@ -1848,7 +1872,7 @@
                 final int dataRat = getRilDataRadioTechnologyForWwan(mNewSS);
                 if (ServiceState.isCdma(dataRat)) {
                     final boolean isVoiceInService =
-                            (mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+                            (mNewSS.getState() == ServiceState.STATE_IN_SERVICE);
                     if (isVoiceInService) {
                         boolean isVoiceRoaming = mNewSS.getVoiceRoaming();
                         if (mNewSS.getDataRoaming() != isVoiceRoaming) {
@@ -1887,9 +1911,9 @@
                         // Use default
                         mNewSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator);
                     } else if (namMatch && !mIsInPrl) {
-                        // TODO this will be removed when we handle roaming on LTE on CDMA+LTE phones
-                        if (ServiceState.isLte(mNewSS.getRilVoiceRadioTechnology())) {
-                            log("Turn off roaming indicator as voice is LTE");
+                        // TODO: remove when we handle roaming on LTE/NR on CDMA+LTE phones
+                        if (ServiceState.isPsOnlyTech(mNewSS.getRilVoiceRadioTechnology())) {
+                            log("Turn off roaming indicator as voice is LTE or NR");
                             mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
                         } else {
                             mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
@@ -2077,9 +2101,6 @@
 
                     mGsmRoaming = regCodeIsRoaming(registrationState);
                     mNewRejectCode = reasonForDenial;
-
-                    boolean isVoiceCapable = mPhone.getContext().getResources()
-                            .getBoolean(com.android.internal.R.bool.config_voice_capable);
                 } else {
                     int roamingIndicator = voiceSpecificStates.roamingIndicator;
 
@@ -2150,6 +2171,7 @@
                 int serviceState = regCodeToServiceState(registrationState);
                 int newDataRat = ServiceState.networkTypeToRilRadioTechnology(
                         networkRegState.getAccessNetworkTechnology());
+                boolean nrHasChanged = false;
 
                 if (DBG) {
                     log("handlePollStateResultMessage: PS cellular. " + networkRegState);
@@ -2160,11 +2182,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();
@@ -2177,16 +2205,17 @@
                 } else {
 
                     // If the unsolicited signal strength comes just before data RAT family changes
-                    // (i.e. from UNKNOWN to LTE, CDMA to LTE, LTE to CDMA), the signal bar might
-                    // display the wrong information until the next unsolicited signal strength
-                    // information coming from the modem, which might take a long time to come or
-                    // even not come at all.  In order to provide the best user experience, we
-                    // query the latest signal information so it will show up on the UI on time.
+                    // (i.e. from UNKNOWN to LTE/NR, CDMA to LTE/NR, LTE/NR to CDMA), the signal bar
+                    // might display the wrong information until the next unsolicited signal
+                    // strength information coming from the modem, which might take a long time to
+                    // come or even not come at all.  In order to provide the best user experience,
+                    // we query the latest signal information so it will show up on the UI on time.
                     int oldDataRAT = getRilDataRadioTechnologyForWwan(mSS);
                     if (((oldDataRAT == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)
                             && (newDataRat != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN))
-                            || (ServiceState.isCdma(oldDataRAT) && ServiceState.isLte(newDataRat))
-                            || (ServiceState.isLte(oldDataRAT)
+                            || (ServiceState.isCdma(oldDataRAT)
+                            && ServiceState.isPsOnlyTech(newDataRat))
+                            || (ServiceState.isPsOnlyTech(oldDataRAT)
                             && ServiceState.isCdma(newDataRat))) {
                         mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
                     }
@@ -2202,8 +2231,6 @@
             }
 
             case EVENT_POLL_STATE_OPERATOR: {
-                String brandOverride = getOperatorBrandOverride();
-                mCdnr.updateEfForBrandOverride(brandOverride);
                 if (mPhone.isPhoneTypeGsm()) {
                     String opNames[] = (String[]) ar.result;
 
@@ -2211,6 +2238,8 @@
                         mNewSS.setOperatorAlphaLongRaw(opNames[0]);
                         mNewSS.setOperatorAlphaShortRaw(opNames[1]);
                         // FIXME: Giving brandOverride higher precedence, is this desired?
+                        String brandOverride = getOperatorBrandOverride();
+                        mCdnr.updateEfForBrandOverride(brandOverride);
                         if (brandOverride != null) {
                             log("EVENT_POLL_STATE_OPERATOR: use brandOverride=" + brandOverride);
                             mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
@@ -2240,6 +2269,8 @@
                             // NV device (as opposed to CSIM)
                             mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
                         } else {
+                            String brandOverride = getOperatorBrandOverride();
+                            mCdnr.updateEfForBrandOverride(brandOverride);
                             if (brandOverride != null) {
                                 mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
                             } else {
@@ -2465,7 +2496,8 @@
                 setRoamingOn();
             }
 
-            if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
+            if (TelephonyUtils.IS_DEBUGGABLE
+                    && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
                 mNewSS.setVoiceRoaming(true);
                 mNewSS.setDataRoaming(true);
             }
@@ -2705,7 +2737,7 @@
                 // is satisfied or SPN override is enabled for this carrier.
 
                 // Handle Flight Mode
-                if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF) {
+                if (mSS.getState() == ServiceState.STATE_POWER_OFF) {
                     wfcVoiceSpnFormat = wfcFlightSpnFormat;
                 }
 
@@ -2718,7 +2750,7 @@
                 // Show PLMN + Wi-Fi Calling if there is no valid SPN in the above case
                 String originalPlmn = plmn.trim();
                 plmn = String.format(wfcVoiceSpnFormat, originalPlmn);
-            } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF
+            } else if (mSS.getState() == ServiceState.STATE_POWER_OFF
                     || (showPlmn && TextUtils.equals(spn, plmn))) {
                 // airplane mode or spn equals plmn, do not show spn
                 spn = null;
@@ -2920,7 +2952,7 @@
      */
     @UnsupportedAppUsage
     public int getCurrentDataConnectionState() {
-        return mSS.getDataRegState();
+        return mSS.getDataRegistrationState();
     }
 
     /**
@@ -2937,7 +2969,7 @@
             // There are cases where we we would setup data connection even data is not yet
             // attached. In these cases we check voice rat.
             if (radioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
-                    && mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE) {
+                    && mSS.getDataRegistrationState() != ServiceState.STATE_IN_SERVICE) {
                 radioTechnology = mSS.getRilVoiceRadioTechnology();
             }
             // Concurrent voice and data is not allowed for 2G technologies. It's allowed in other
@@ -2992,18 +3024,10 @@
      */
     @UnsupportedAppUsage
     public void pollState() {
-        pollState(false);
-    }
-    /**
-     * We insist on polling even if the radio says its off.
-     * Used when we get a network changed notification
-     * but the radio is off - part of iwlan hack
-     */
-    private void modemTriggeredPollState() {
-        pollState(true);
+        sendEmptyMessage(EVENT_POLL_STATE_REQUEST);
     }
 
-    public void pollState(boolean modemTriggered) {
+    private void pollStateInternal(boolean modemTriggered) {
         mPollingContext = new int[1];
         mPollingContext[0] = 0;
 
@@ -3014,7 +3038,8 @@
                 mNewSS.setStateOutOfService();
                 mNewCellIdentity = null;
                 setSignalStrengthDefaultValues();
-                mNitzState.handleCountryUnavailable();
+                mLastNitzData = null;
+                mNitzState.handleNetworkUnavailable();
                 pollStateDone();
                 break;
 
@@ -3022,7 +3047,8 @@
                 mNewSS.setStateOff();
                 mNewCellIdentity = null;
                 setSignalStrengthDefaultValues();
-                mNitzState.handleCountryUnavailable();
+                mLastNitzData = null;
+                mNitzState.handleNetworkUnavailable();
                 // don't poll when device is shutting down or the poll was not modemTrigged
                 // (they sent us new radio data) and current network is not IWLAN
                 if (mDeviceShuttingDown ||
@@ -3071,14 +3097,15 @@
             updateRoamingState();
         }
 
-        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
+        if (TelephonyUtils.IS_DEBUGGABLE
+                && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
             mNewSS.setVoiceRoaming(true);
             mNewSS.setDataRoaming(true);
         }
         useDataRegStateForDataOnlyDevices();
         processIwlanRegistrationInfo();
 
-        if (Build.IS_DEBUGGABLE && mPhone.mTelephonyTester != null) {
+        if (TelephonyUtils.IS_DEBUGGABLE && mPhone.mTelephonyTester != null) {
             mPhone.mTelephonyTester.overrideServiceState(mNewSS);
         }
 
@@ -3088,20 +3115,21 @@
                     + " oldMaxDataCalls=" + mMaxDataCalls
                     + " mNewMaxDataCalls=" + mNewMaxDataCalls
                     + " oldReasonDataDenied=" + mReasonDataDenied
-                    + " mNewReasonDataDenied=" + mNewReasonDataDenied);
+                    + " mNewReasonDataDeni"
+                    + "ed=" + mNewReasonDataDenied);
         }
 
         boolean hasRegistered =
-                mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
-                        && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
+                mSS.getState() != ServiceState.STATE_IN_SERVICE
+                        && mNewSS.getState() == ServiceState.STATE_IN_SERVICE;
 
         boolean hasDeregistered =
-                mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
-                        && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
+                mSS.getState() == ServiceState.STATE_IN_SERVICE
+                        && mNewSS.getState() != ServiceState.STATE_IN_SERVICE;
 
         boolean hasAirplaneModeOnChanged =
-                mSS.getVoiceRegState() != ServiceState.STATE_POWER_OFF
-                        && mNewSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF;
+                mSS.getState() != ServiceState.STATE_POWER_OFF
+                        && mNewSS.getState() == ServiceState.STATE_POWER_OFF;
 
         SparseBooleanArray hasDataAttached = new SparseBooleanArray(
                 mTransportManager.getAvailableTransports().length);
@@ -3157,7 +3185,7 @@
                 && (mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology());
 
         boolean hasVoiceRegStateChanged =
-                mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
+                mSS.getState() != mNewSS.getState();
 
         boolean hasNrFrequencyRangeChanged =
                 mSS.getNrFrequencyRange() != mNewSS.getNrFrequencyRange();
@@ -3176,7 +3204,8 @@
 
         // ratchet the new tech up through its rat family but don't drop back down
         // until cell change or device is OOS
-        boolean isDataInService = mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
+        boolean isDataInService = mNewSS.getDataRegistrationState()
+                == ServiceState.STATE_IN_SERVICE;
         if (isDataInService) {
             mRatRatcheter.ratchet(mSS, mNewSS, hasLocationChanged);
         }
@@ -3204,17 +3233,15 @@
         if (mPhone.isPhoneTypeCdmaLte()) {
             final int wwanDataRat = getRilDataRadioTechnologyForWwan(mSS);
             final int newWwanDataRat = getRilDataRadioTechnologyForWwan(mNewSS);
-            has4gHandoff = mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
-                    && ((ServiceState.isLte(wwanDataRat)
+            has4gHandoff = mNewSS.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE
+                    && ((ServiceState.isPsOnlyTech(wwanDataRat)
                     && (newWwanDataRat == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD))
-                    ||
-                    ((wwanDataRat == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)
-                    && ServiceState.isLte(newWwanDataRat)));
+                    || ((wwanDataRat == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)
+                    && ServiceState.isPsOnlyTech(newWwanDataRat)));
 
-            hasMultiApnSupport = ((ServiceState.isLte(newWwanDataRat)
+            hasMultiApnSupport = ((ServiceState.isPsOnlyTech(newWwanDataRat)
                     || (newWwanDataRat == ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD))
-                    &&
-                    (!ServiceState.isLte(wwanDataRat)
+                    && (!ServiceState.isPsOnlyTech(wwanDataRat)
                     && (wwanDataRat != ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD)));
 
             hasLostMultiApnSupport = ((newWwanDataRat >= ServiceState.RIL_RADIO_TECHNOLOGY_IS95A)
@@ -3250,8 +3277,8 @@
         if (hasVoiceRegStateChanged || anyDataRegChanged) {
             EventLog.writeEvent(mPhone.isPhoneTypeGsm() ? EventLogTags.GSM_SERVICE_STATE_CHANGE :
                             EventLogTags.CDMA_SERVICE_STATE_CHANGE,
-                    mSS.getVoiceRegState(), mSS.getDataRegState(),
-                    mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
+                    mSS.getState(), mSS.getDataRegistrationState(),
+                    mNewSS.getState(), mNewSS.getDataRegistrationState());
         }
 
         if (mPhone.isPhoneTypeGsm()) {
@@ -3278,7 +3305,7 @@
             }
 
             if (hasCssIndicatorChanged) {
-                mPhone.notifyDataConnection();
+                mPhone.notifyAllActiveDataConnections();
             }
 
             mReasonDataDenied = mNewReasonDataDenied;
@@ -3398,7 +3425,9 @@
             mPhone.getContext().getContentResolver()
                     .insert(getUriForSubscriptionId(mPhone.getSubId()),
                             getContentValuesForServiceState(mSS));
+        }
 
+        if (hasChanged || hasNrStateChanged) {
             TelephonyMetrics.getInstance().writeServiceStateChanged(mPhone.getPhoneId(), mSS);
         }
 
@@ -3432,7 +3461,7 @@
                     // that ServiceState#getRilDataRadioTechnology has changed.
                     || hasDataTransportPreferenceChanged) {
                 notifyDataRegStateRilRadioTechnologyChanged(transport);
-                mPhone.notifyDataConnection();
+                mPhone.notifyAllActiveDataConnections();
             }
 
             if (hasDataAttached.get(transport)) {
@@ -3481,11 +3510,11 @@
         }
 
         if (hasLocationChanged) {
-            mPhone.notifyLocationChanged(getCellLocation());
+            mPhone.notifyLocationChanged(getCellIdentity());
         }
 
         if (mPhone.isPhoneTypeGsm()) {
-            if (!isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
+            if (!isGprsConsistent(mSS.getDataRegistrationState(), mSS.getState())) {
                 if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
                     mStartedGprsRegCheck = true;
 
@@ -3508,7 +3537,7 @@
             if ((mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON)
                     && (!mIsSubscriptionFromRuim)) {
                 // Now the Phone sees the new ServiceState so it can get the new ERI text
-                if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+                if (mSS.getState() == ServiceState.STATE_IN_SERVICE) {
                     eriText = mPhone.getCdmaEriText();
                 } else {
                     // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used for
@@ -3522,22 +3551,22 @@
                     mUiccController.getUiccCard(getPhoneId()).getOperatorBrandOverride() != null;
             if (!hasBrandOverride && (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON)
                     && (mEriManager.isEriFileLoaded())
-                    && (!ServiceState.isLte(mSS.getRilVoiceRadioTechnology())
+                    && (!ServiceState.isPsOnlyTech(mSS.getRilVoiceRadioTechnology())
                     || mPhone.getContext().getResources().getBoolean(com.android.internal.R
                     .bool.config_LTE_eri_for_network_name))) {
                 // Only when CDMA is in service, ERI will take effect
                 eriText = mSS.getOperatorAlpha();
                 // Now the Phone sees the new ServiceState so it can get the new ERI text
-                if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+                if (mSS.getState() == ServiceState.STATE_IN_SERVICE) {
                     eriText = mPhone.getCdmaEriText();
-                } else if (mSS.getVoiceRegState() == ServiceState.STATE_POWER_OFF) {
+                } else if (mSS.getState() == ServiceState.STATE_POWER_OFF) {
                     eriText = getServiceProviderName();
                     if (TextUtils.isEmpty(eriText)) {
                         // Sets operator alpha property by retrieving from
                         // build-time system property
                         eriText = SystemProperties.get("ro.cdma.home.operator.alpha");
                     }
-                } else if (mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE) {
+                } else if (mSS.getDataRegistrationState() != ServiceState.STATE_IN_SERVICE) {
                     // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used
                     // for mRegistrationState 0,2,3 and 4
                     eriText = mPhone.getContext()
@@ -3547,7 +3576,7 @@
 
             if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY &&
                     mIccRecords != null && getCombinedRegState(mSS) == ServiceState.STATE_IN_SERVICE
-                    && !ServiceState.isLte(mSS.getRilVoiceRadioTechnology())) {
+                    && !ServiceState.isPsOnlyTech(mSS.getRilVoiceRadioTechnology())) {
                 // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches
                 // one configured in SIM, use operator name from CSIM record. Note that ERI, SID,
                 // and NID are CDMA only, not applicable to LTE.
@@ -3686,16 +3715,19 @@
 
     @UnsupportedAppUsage
     protected void setOperatorIdd(String operatorNumeric) {
+        if (mPhone.getUnitTestMode()) {
+            return;
+        }
+
         // Retrieve the current country information
         // with the MCC got from opeatorNumeric.
         String idd = mHbpcdUtils.getIddByMcc(
                 Integer.parseInt(operatorNumeric.substring(0,3)));
         if (idd != null && !idd.isEmpty()) {
-            mPhone.setGlobalSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING,
-                    idd);
+            TelephonyProperties.operator_idp_string(idd);
         } else {
             // use default "+", since we don't know the current IDP
-            mPhone.setGlobalSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING, "+");
+            TelephonyProperties.operator_idp_string("+");
         }
     }
 
@@ -3955,9 +3987,9 @@
     }
 
     /**
-     * Get CellLocation from the ServiceState if available or guess from cached CellInfo
+     * Get CellIdentity from the ServiceState if available or guess from cached
      *
-     * Get the CellLocation by first checking if ServiceState has a current CID. If so
+     * Get the CellIdentity by first checking if ServiceState has a current CID. If so
      * then return that info. Otherwise, check the latest List<CellInfo> and return the first GSM or
      * WCDMA result that appears. If no GSM or WCDMA results, then return an LTE result. The
      * behavior is kept consistent for backwards compatibility; (do not apply logic to determine
@@ -3965,18 +3997,19 @@
      *
      * @return the current cell location if known or a non-null "empty" cell location
      */
-    public CellLocation getCellLocation() {
-        if (mCellIdentity != null) return mCellIdentity.asCellLocation();
+    @NonNull
+    public CellIdentity getCellIdentity() {
+        if (mCellIdentity != null) return mCellIdentity;
 
-        CellLocation cl = getCellLocationFromCellInfo(getAllCellInfo());
-        if (cl != null) return cl;
+        CellIdentity ci = getCellIdentityFromCellInfo(getAllCellInfo());
+        if (ci != null) return ci;
 
         return mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA
-                ? new CdmaCellLocation() : new GsmCellLocation();
+                ? new CellIdentityCdma() : new CellIdentityGsm();
     }
 
     /**
-     * Get CellLocation from the ServiceState if available or guess from CellInfo
+     * Get CellIdentity from the ServiceState if available or guess from CellInfo
      *
      * Get the CellLocation by first checking if ServiceState has a current CID. If so
      * then return that info. Otherwise, query AllCellInfo and return the first GSM or
@@ -3987,9 +4020,9 @@
      * @param workSource calling WorkSource
      * @param rspMsg the response message which must be non-null
      */
-    public void requestCellLocation(WorkSource workSource, Message rspMsg) {
+    public void requestCellIdentity(WorkSource workSource, Message rspMsg) {
         if (mCellIdentity != null) {
-            AsyncResult.forMessage(rspMsg, mCellIdentity.asCellLocation(), null);
+            AsyncResult.forMessage(rspMsg, mCellIdentity, null);
             rspMsg.sendToTarget();
             return;
         }
@@ -3998,16 +4031,16 @@
         requestAllCellInfo(workSource, cellLocRsp);
     }
 
-    /* Find and return a CellLocation from CellInfo
+    /* Find and return a CellIdentity from CellInfo
      *
      * This method returns the first GSM or WCDMA result that appears in List<CellInfo>. If no GSM
      * or  WCDMA results are found, then it returns an LTE result. The behavior is kept consistent
      * for backwards compatibility; (do not apply logic to determine why the behavior is this way).
      *
-     * @return the current cell location from CellInfo or null
+     * @return the current CellIdentity from CellInfo or null
      */
-    private static CellLocation getCellLocationFromCellInfo(List<CellInfo> info) {
-        CellLocation cl = null;
+    private static CellIdentity getCellIdentityFromCellInfo(List<CellInfo> info) {
+        CellIdentity cl = null;
         if (info != null && info.size() > 0) {
             CellIdentity fallbackLteCid = null; // We prefer not to use LTE
             for (CellInfo ci : info) {
@@ -4017,12 +4050,12 @@
                     continue;
                 }
                 if (getCidFromCellIdentity(c) != -1) {
-                    cl = c.asCellLocation();
+                    cl = c;
                     break;
                 }
             }
             if (cl == null && fallbackLteCid != null) {
-                cl = fallbackLteCid.asCellLocation();
+                cl = fallbackLteCid;
             }
         }
         return cl;
@@ -4087,7 +4120,8 @@
         Context context = mPhone.getContext();
 
         SubscriptionInfo info = mSubscriptionController
-                .getActiveSubscriptionInfo(mPhone.getSubId(), context.getOpPackageName());
+                .getActiveSubscriptionInfo(mPhone.getSubId(), context.getOpPackageName(),
+                        null);
 
         //if subscription is part of a group and non-primary, suppress all notifications
         if (info == null || (info.isOpportunistic() && info.getGroupUuid() != null)) {
@@ -4446,7 +4480,7 @@
         Registrant r = new Registrant(h, what, obj);
 
         mNetworkAttachedRegistrants.add(r);
-        if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+        if (mSS.getState() == ServiceState.STATE_IN_SERVICE) {
             r.notifyRegistrant();
         }
     }
@@ -4465,7 +4499,7 @@
         Registrant r = new Registrant(h, what, obj);
 
         mNetworkDetachedRegistrants.add(r);
-        if (mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE) {
+        if (mSS.getState() != ServiceState.STATE_IN_SERVICE) {
             r.notifyRegistrant();
         }
     }
@@ -4696,7 +4730,7 @@
         // Sometimes the network registration information comes before carrier config is ready.
         // For some cases like roaming/non-roaming overriding, we need carrier config. So it's
         // important to poll state again when carrier config is ready.
-        pollState();
+        pollStateInternal(false);
     }
 
     private void updateLteEarfcnLists(PersistableBundle config) {
@@ -4710,12 +4744,44 @@
     }
 
     private void updateReportingCriteria(PersistableBundle config) {
-        mPhone.setSignalStrengthReportingCriteria(
+        int lteMeasurementEnabled = config.getInt(CarrierConfigManager
+                .KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT, CellSignalStrengthLte.USE_RSRP);
+        mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSRP,
                 config.getIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY),
-                AccessNetworkType.EUTRAN);
-        mPhone.setSignalStrengthReportingCriteria(
+                AccessNetworkType.EUTRAN,
+                (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSRP) != 0);
+        mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSCP,
                 config.getIntArray(CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY),
-                AccessNetworkType.UTRAN);
+                AccessNetworkType.UTRAN, true);
+        mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSSI,
+                config.getIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY),
+                AccessNetworkType.GERAN, true);
+
+        if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSRQ,
+                    config.getIntArray(CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY),
+                    AccessNetworkType.EUTRAN,
+                    (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSRQ) != 0);
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_RSSNR,
+                    config.getIntArray(CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY),
+                    AccessNetworkType.EUTRAN,
+                    (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSSNR) != 0);
+
+            int measurementEnabled = config.getInt(CarrierConfigManager
+                    .KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, CellSignalStrengthNr.USE_SSRSRP);
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_SSRSRP,
+                    config.getIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY),
+                    AccessNetworkType.NGRAN,
+                    (measurementEnabled & CellSignalStrengthNr.USE_SSRSRP) != 0);
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_SSRSRQ,
+                    config.getIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY),
+                    AccessNetworkType.NGRAN,
+                    (measurementEnabled & CellSignalStrengthNr.USE_SSRSRQ) != 0);
+            mPhone.setSignalStrengthReportingCriteria(SignalThresholdInfo.SIGNAL_SSSINR,
+                    config.getIntArray(CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY),
+                    AccessNetworkType.NGRAN,
+                    (measurementEnabled & CellSignalStrengthNr.USE_SSSINR) != 0);
+        }
     }
 
     private void updateServiceStateLteEarfcnBoost(ServiceState serviceState, int lteEarfcn) {
@@ -4899,7 +4965,8 @@
         if (!isStale) return false;
 
         List<SubscriptionInfo> subInfoList = SubscriptionController.getInstance()
-                .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName());
+                .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(),
+                        null);
         for (SubscriptionInfo info : subInfoList) {
             // If we have an active opportunistic subscription whose data is IN_SERVICE, we needs
             // to get signal strength to decide data switching threshold. In this case, we poll
@@ -4908,7 +4975,7 @@
                 TelephonyManager tm = TelephonyManager.from(mPhone.getContext())
                         .createForSubscriptionId(info.getSubscriptionId());
                 ServiceState ss = tm.getServiceState();
-                if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
+                if (ss != null && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) {
                     return true;
                 }
             }
@@ -4953,7 +5020,7 @@
         mCi.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
 
         // Get Registration Information
-        pollState();
+        pollStateInternal(false);
     }
 
     private void handleCdmaSubscriptionSource(int newSubscriptionSource) {
@@ -5179,12 +5246,12 @@
     @UnsupportedAppUsage
     protected void setRoamingType(ServiceState currentServiceState) {
         final boolean isVoiceInService =
-                (currentServiceState.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+                (currentServiceState.getState() == ServiceState.STATE_IN_SERVICE);
         if (isVoiceInService) {
             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 {
@@ -5208,7 +5275,7 @@
                         }
                     } else {
                         // check roaming type by MCC
-                        if (inSameCountry(currentServiceState.getVoiceOperatorNumeric())) {
+                        if (inSameCountry(currentServiceState.getOperatorNumeric())) {
                             currentServiceState.setVoiceRoamingType(
                                     ServiceState.ROAMING_TYPE_DOMESTIC);
                         } else {
@@ -5222,7 +5289,7 @@
             }
         }
         final boolean isDataInService =
-                (currentServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE);
+                (currentServiceState.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE);
         final int dataRegType = getRilDataRadioTechnologyForWwan(currentServiceState);
         if (isDataInService) {
             if (!currentServiceState.getDataRoaming()) {
@@ -5255,7 +5322,7 @@
                         }
                     } else {
                         // take it as 3GPP roaming
-                        if (inSameCountry(currentServiceState.getDataOperatorNumeric())) {
+                        if (inSameCountry(currentServiceState.getOperatorNumeric())) {
                             currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_DOMESTIC);
                         } else {
                             currentServiceState.setDataRoamingType(
@@ -5423,8 +5490,8 @@
      * @param ss service state.
      */
     protected int getCombinedRegState(ServiceState ss) {
-        int regState = ss.getVoiceRegState();
-        int dataRegState = ss.getDataRegState();
+        int regState = ss.getState();
+        int dataRegState = ss.getDataRegistrationState();
         if ((regState == ServiceState.STATE_OUT_OF_SERVICE
                 || regState == ServiceState.STATE_POWER_OFF)
                 && (dataRegState == ServiceState.STATE_IN_SERVICE)) {
@@ -5591,4 +5658,31 @@
 
         return idSet;
     }
+
+    private void setDataNetworkTypeForPhone(int type) {
+        if (mPhone.getUnitTestMode()) {
+            return;
+        }
+        TelephonyManager tm = (TelephonyManager) mPhone.getContext().getSystemService(
+                Context.TELEPHONY_SERVICE);
+        tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), type);
+    }
+
+    /**
+     * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
+     *
+     * Copied from packages/services/Telephony/src/com/android/phone/ServiceStateProvider.java
+     *
+     * @param state the ServiceState to convert into ContentValues
+     * @return the convertedContentValues instance
+     */
+    private ContentValues getContentValuesForServiceState(ServiceState state) {
+        ContentValues values = new ContentValues();
+        final Parcel p = Parcel.obtain();
+        state.writeToParcel(p, 0);
+        // Turn the parcel to byte array. Safe to do this because the content values were never
+        // written into a persistent storage. ServiceStateProvider keeps values in the memory.
+        values.put(SERVICE_STATE, p.marshall());
+        return values;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/SettingsObserver.java b/src/java/com/android/internal/telephony/SettingsObserver.java
index 2253c36..e480b05 100644
--- a/src/java/com/android/internal/telephony/SettingsObserver.java
+++ b/src/java/com/android/internal/telephony/SettingsObserver.java
@@ -21,7 +21,8 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/src/java/com/android/internal/telephony/SimActivationTracker.java b/src/java/com/android/internal/telephony/SimActivationTracker.java
index 8fd6eed..2daf858 100644
--- a/src/java/com/android/internal/telephony/SimActivationTracker.java
+++ b/src/java/com/android/internal/telephony/SimActivationTracker.java
@@ -15,25 +15,24 @@
  */
 package com.android.internal.telephony;
 
+import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED;
+import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATING;
+import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED;
+import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_RESTRICTED;
+import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.telephony.Rlog;
 import android.util.LocalLog;
 import android.util.Log;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.security.InvalidParameterException;
-
-import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED;
-import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED;
-import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
-import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_RESTRICTED;
-import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATING;
 
 public class SimActivationTracker {
     /**
diff --git a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
index a1d8faa..445b0ef 100644
--- a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
+++ b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -27,12 +27,12 @@
 import android.os.PersistableBundle;
 import android.os.UserManager;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 
 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
 import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.telephony.Rlog;
 
 import java.util.HashMap;
 import java.util.HashSet;
diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java
index 0fce4d2..6c71690 100644
--- a/src/java/com/android/internal/telephony/SmsController.java
+++ b/src/java/com/android/internal/telephony/SmsController.java
@@ -18,28 +18,28 @@
 
 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.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.net.Uri;
+import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.ServiceManager;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.IFinancialSmsCallback;
-import android.telephony.Rlog;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SmsManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -80,6 +80,9 @@
     @Override
     public boolean updateMessageOnIccEfForSubscriber(int subId, String callingPackage, int index,
             int status, byte[] pdu) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             return iccSmsIntMgr.updateMessageOnIccEf(callingPackage, index, status, pdu);
@@ -94,6 +97,9 @@
     @Override
     public boolean copyMessageToIccEfForSubscriber(int subId, String callingPackage, int status,
             byte[] pdu, byte[] smsc) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             return iccSmsIntMgr.copyMessageToIccEf(callingPackage, status, pdu, smsc);
@@ -107,6 +113,9 @@
     @UnsupportedAppUsage
     @Override
     public List<SmsRawData> getAllMessagesFromIccEfForSubscriber(int subId, String callingPackage) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             return iccSmsIntMgr.getAllMessagesFromIccEf(callingPackage);
@@ -122,6 +131,9 @@
     public void sendDataForSubscriber(int subId, String callingPackage, String destAddr,
             String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
             PendingIntent deliveryIntent) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             iccSmsIntMgr.sendData(callingPackage, destAddr, scAddr, destPort, data,
@@ -156,10 +168,17 @@
         }
     }
 
+    private String getCallingPackage() {
+        return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid())[0];
+    }
+
     @Override
     public void sendTextForSubscriber(int subId, String callingPackage, String destAddr,
             String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
             boolean persistMessageForNonDefaultSmsApp) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         if (!getSmsPermissions(subId).checkCallingCanSendText(persistMessageForNonDefaultSmsApp,
                 callingPackage, "Sending SMS message")) {
             sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
@@ -189,7 +208,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,
@@ -233,6 +252,9 @@
             String destAddr, String scAddr, String parts, PendingIntent sentIntent,
             PendingIntent deliveryIntent, boolean persistMessage, int priority,
             boolean expectMore, int validityPeriod) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             iccSmsIntMgr.sendTextWithOptions(callingPackage, destAddr, scAddr, parts, sentIntent,
@@ -248,6 +270,11 @@
     public void sendMultipartTextForSubscriber(int subId, String callingPackage, String destAddr,
             String scAddr, List<String> parts, List<PendingIntent> sentIntents,
             List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp) {
+        // This is different from the checking of other method. It prefers the package name
+        // returned by getCallPackage() for backward-compatibility.
+        if (getCallingPackage() != null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             iccSmsIntMgr.sendMultipartText(callingPackage, destAddr, scAddr, parts, sentIntents,
@@ -264,6 +291,9 @@
             String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents,
             List<PendingIntent> deliveryIntents, boolean persistMessage, int priority,
             boolean expectMore, int validityPeriod) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             iccSmsIntMgr.sendMultipartTextWithOptions(callingPackage, destAddr, scAddr, parts,
@@ -367,7 +397,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
@@ -502,29 +532,155 @@
     }
 
     @Override
+    public Bundle getCarrierConfigValuesForSubscriber(int subId) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final CarrierConfigManager configManager =
+                    (CarrierConfigManager)
+                            mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            return getMmsConfig(configManager.getConfigForSubId(subId));
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Filters a bundle to only contain MMS config variables.
+     *
+     * This is for use with bundles returned by CarrierConfigManager which contain MMS config and
+     * unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the supplied
+     * bundle.
+     *
+     * @param config a Bundle that contains MMS config variables and possibly more.
+     * @return a new Bundle that only contains the MMS_CONFIG_* keys defined in SmsManager.
+     */
+    private static Bundle getMmsConfig(BaseBundle config) {
+        Bundle filtered = new Bundle();
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_APPEND_TRANSACTION_ID,
+                config.getBoolean(SmsManager.MMS_CONFIG_APPEND_TRANSACTION_ID));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_MMS_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_MMS_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_GROUP_MMS_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_GROUP_MMS_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_ALIAS_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_ALIAS_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_ALLOW_ATTACH_AUDIO,
+                config.getBoolean(SmsManager.MMS_CONFIG_ALLOW_ATTACH_AUDIO));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_MULTIPART_SMS_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_MULTIPART_SMS_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
+                config.getBoolean(SmsManager.MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
+                config.getBoolean(SmsManager.MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_MMS_READ_REPORT_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_MMS_READ_REPORT_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED,
+                config.getBoolean(SmsManager.MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_CLOSE_CONNECTION,
+                config.getBoolean(SmsManager.MMS_CONFIG_CLOSE_CONNECTION));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_MAX_MESSAGE_SIZE,
+                config.getInt(SmsManager.MMS_CONFIG_MAX_MESSAGE_SIZE));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_MAX_IMAGE_WIDTH,
+                config.getInt(SmsManager.MMS_CONFIG_MAX_IMAGE_WIDTH));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_MAX_IMAGE_HEIGHT,
+                config.getInt(SmsManager.MMS_CONFIG_MAX_IMAGE_HEIGHT));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_RECIPIENT_LIMIT,
+                config.getInt(SmsManager.MMS_CONFIG_RECIPIENT_LIMIT));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_ALIAS_MIN_CHARS,
+                config.getInt(SmsManager.MMS_CONFIG_ALIAS_MIN_CHARS));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_ALIAS_MAX_CHARS,
+                config.getInt(SmsManager.MMS_CONFIG_ALIAS_MAX_CHARS));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD,
+                config.getInt(SmsManager.MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
+                config.getInt(SmsManager.MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE,
+                config.getInt(SmsManager.MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_SUBJECT_MAX_LENGTH,
+                config.getInt(SmsManager.MMS_CONFIG_SUBJECT_MAX_LENGTH));
+        filtered.putInt(
+                SmsManager.MMS_CONFIG_HTTP_SOCKET_TIMEOUT,
+                config.getInt(SmsManager.MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
+        filtered.putString(
+                SmsManager.MMS_CONFIG_UA_PROF_TAG_NAME,
+                config.getString(SmsManager.MMS_CONFIG_UA_PROF_TAG_NAME));
+        filtered.putString(
+                SmsManager.MMS_CONFIG_USER_AGENT,
+                config.getString(SmsManager.MMS_CONFIG_USER_AGENT));
+        filtered.putString(
+                SmsManager.MMS_CONFIG_UA_PROF_URL,
+                config.getString(SmsManager.MMS_CONFIG_UA_PROF_URL));
+        filtered.putString(
+                SmsManager.MMS_CONFIG_HTTP_PARAMS,
+                config.getString(SmsManager.MMS_CONFIG_HTTP_PARAMS));
+        filtered.putString(
+                SmsManager.MMS_CONFIG_EMAIL_GATEWAY_NUMBER,
+                config.getString(SmsManager.MMS_CONFIG_EMAIL_GATEWAY_NUMBER));
+        filtered.putString(
+                SmsManager.MMS_CONFIG_NAI_SUFFIX,
+                config.getString(SmsManager.MMS_CONFIG_NAI_SUFFIX));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS,
+                config.getBoolean(SmsManager.MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS));
+        filtered.putBoolean(
+                SmsManager.MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER,
+                config.getBoolean(SmsManager.MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER));
+        return filtered;
+    }
+
+    @Override
     public String createAppSpecificSmsTokenWithPackageInfo(
             int subId, String callingPkg, String prefixes, PendingIntent intent) {
+        if (callingPkg == null) {
+            callingPkg = getCallingPackage();
+        }
         return getPhone(subId).getAppSmsManager().createAppSpecificSmsTokenWithPackageInfo(
                 subId, callingPkg, prefixes, intent);
     }
 
     @Override
     public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) {
+        if (callingPkg == null) {
+            callingPkg = getCallingPackage();
+        }
         return getPhone(subId).getAppSmsManager().createAppSpecificSmsToken(callingPkg, intent);
     }
 
     @Override
-    public void getSmsMessagesForFinancialApp(
-            int subId, String callingPkg, Bundle params, IFinancialSmsCallback callback) {
-        getPhone(subId).getAppSmsManager().getSmsMessagesForFinancialApp(
-                callingPkg, params, callback);
-    }
-
-    @Override
-    public int checkSmsShortCodeDestination(
-            int subId, String callingPackage, String destAddress, String countryIso) {
+    public int checkSmsShortCodeDestination(int subId, String callingPackage,
+            String callingFeatureId, String destAddress, String countryIso) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(getPhone(subId).getContext(),
-                subId, callingPackage, "checkSmsShortCodeDestination")) {
+                subId, callingPackage, callingFeatureId, "checkSmsShortCodeDestination")) {
             return SmsManager.SMS_CATEGORY_NOT_SHORT_CODE;
         }
         final long identity = Binder.clearCallingIdentity();
@@ -551,11 +707,11 @@
         }
     }
 
-    /**
-     * Triggered by `adb shell dumpsys isms`
-     */
     @Override
     public String getSmscAddressFromIccEfForSubscriber(int subId, String callingPackage) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             return iccSmsIntMgr.getSmscAddressFromIccEf(callingPackage);
@@ -569,6 +725,9 @@
     @Override
     public boolean setSmscAddressOnIccEfForSubscriber(
             String smsc, int subId, String callingPackage) {
+        if (callingPackage == null) {
+            callingPackage = getCallingPackage();
+        }
         IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
         if (iccSmsIntMgr != null) {
             return iccSmsIntMgr.setSmscAddressOnIccEf(callingPackage, smsc);
@@ -579,6 +738,9 @@
         }
     }
 
+    /**
+     * Triggered by `adb shell dumpsys isms`
+     */
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!checkDumpPermission(mContext, LOG_TAG, pw)) {
@@ -635,4 +797,19 @@
                 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
         return manager.getActiveSubscriptionInfo(subId);
     }
+
+    /**
+     * Get the capacity count of sms on Icc card.
+     */
+    @Override
+    public int getSmsCapacityOnIccForSubscriber(int subId) {
+        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
+
+        if (iccSmsIntMgr != null ) {
+            return iccSmsIntMgr.getSmsCapacityOnIcc();
+        } else {
+            Rlog.e(LOG_TAG, "iccSmsIntMgr is null for " + " subId: " + subId);
+            return 0;
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java
index 6b7c8a3..e9ea3d9 100644
--- a/src/java/com/android/internal/telephony/SmsDispatchersController.java
+++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java
@@ -36,7 +36,6 @@
 import android.os.UserManager;
 import android.provider.Telephony.Sms;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
@@ -47,6 +46,7 @@
 import com.android.internal.telephony.cdma.CdmaSMSDispatcher;
 import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
 import com.android.internal.telephony.gsm.GsmSMSDispatcher;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -432,82 +432,81 @@
      */
     public void sendRetrySms(SMSDispatcher.SmsTracker tracker) {
         String oldFormat = tracker.mFormat;
+        boolean retryUsingImsService = false;
 
-        // newFormat will be based on voice technology
+        if (!tracker.mUsesImsServiceForIms && mImsSmsDispatcher.isAvailable()) {
+            // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is
+            // available now, retry this failed tracker using IMS Service.
+            retryUsingImsService = true;
+        }
+
+        // If retryUsingImsService is true, newFormat will be IMS SMS format. Otherwise, newFormat
+        // will be based on voice technology.
         String newFormat =
-                (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType())
-                        ? mCdmaDispatcher.getFormat() : mGsmDispatcher.getFormat();
+                retryUsingImsService
+                        ? mImsSmsDispatcher.getFormat()
+                        : (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType())
+                                ? mCdmaDispatcher.getFormat()
+                                : mGsmDispatcher.getFormat();
 
-        // was previously sent sms format match with voice tech?
-        if (oldFormat.equals(newFormat)) {
-            if (isCdmaFormat(newFormat)) {
-                Rlog.d(TAG, "old format matched new format (cdma)");
-                mCdmaDispatcher.sendSms(tracker);
-                return;
-            } else {
-                Rlog.d(TAG, "old format matched new format (gsm)");
-                mGsmDispatcher.sendSms(tracker);
+        Rlog.d(TAG, "old format(" + oldFormat + ") ==> new format (" + newFormat + ")");
+        if (!oldFormat.equals(newFormat)) {
+            // format didn't match, need to re-encode.
+            HashMap map = tracker.getData();
+
+            // to re-encode, fields needed are: scAddr, destAddr and text if originally sent as
+            // sendText or data and destPort if originally sent as sendData.
+            if (!(map.containsKey("scAddr") && map.containsKey("destAddr")
+                    && (map.containsKey("text")
+                    || (map.containsKey("data") && map.containsKey("destPort"))))) {
+                // should never come here...
+                Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!");
+                tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
                 return;
             }
-        }
+            String scAddr = (String) map.get("scAddr");
+            String destAddr = (String) map.get("destAddr");
 
-        // format didn't match, need to re-encode.
-        HashMap map = tracker.getData();
+            SmsMessageBase.SubmitPduBase pdu = null;
+            // figure out from tracker if this was sendText/Data
+            if (map.containsKey("text")) {
+                Rlog.d(TAG, "sms failed was text");
+                String text = (String) map.get("text");
 
-        // to re-encode, fields needed are:  scAddr, destAddr, and
-        //   text if originally sent as sendText or
-        //   data and destPort if originally sent as sendData.
-        if (!(map.containsKey("scAddr") && map.containsKey("destAddr")
-                && (map.containsKey("text")
-                || (map.containsKey("data") && map.containsKey("destPort"))))) {
-            // should never come here...
-            Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!");
-            tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
-            return;
-        }
-        String scAddr = (String) map.get("scAddr");
-        String destAddr = (String) map.get("destAddr");
+                if (isCdmaFormat(newFormat)) {
+                    pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
+                            scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
+                } else {
+                    pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
+                            scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
+                }
+            } else if (map.containsKey("data")) {
+                Rlog.d(TAG, "sms failed was data");
+                byte[] data = (byte[]) map.get("data");
+                Integer destPort = (Integer) map.get("destPort");
 
-        SmsMessageBase.SubmitPduBase pdu = null;
-        //    figure out from tracker if this was sendText/Data
-        if (map.containsKey("text")) {
-            Rlog.d(TAG, "sms failed was text");
-            String text = (String) map.get("text");
-
-            if (isCdmaFormat(newFormat)) {
-                Rlog.d(TAG, "old format (gsm) ==> new format (cdma)");
-                pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
-                        scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
-            } else {
-                Rlog.d(TAG, "old format (cdma) ==> new format (gsm)");
-                pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
-                        scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null);
-            }
-        } else if (map.containsKey("data")) {
-            Rlog.d(TAG, "sms failed was data");
-            byte[] data = (byte[]) map.get("data");
-            Integer destPort = (Integer) map.get("destPort");
-
-            if (isCdmaFormat(newFormat)) {
-                Rlog.d(TAG, "old format (gsm) ==> new format (cdma)");
-                pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
+                if (isCdmaFormat(newFormat)) {
+                    pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(
                             scAddr, destAddr, destPort.intValue(), data,
                             (tracker.mDeliveryIntent != null));
-            } else {
-                Rlog.d(TAG, "old format (cdma) ==> new format (gsm)");
-                pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
+                } else {
+                    pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(
                             scAddr, destAddr, destPort.intValue(), data,
                             (tracker.mDeliveryIntent != null));
+                }
             }
+
+            // replace old smsc and pdu with newly encoded ones
+            map.put("smsc", pdu.encodedScAddress);
+            map.put("pdu", pdu.encodedMessage);
+            tracker.mFormat = newFormat;
         }
 
-        // replace old smsc and pdu with newly encoded ones
-        map.put("smsc", pdu.encodedScAddress);
-        map.put("pdu", pdu.encodedMessage);
+        SMSDispatcher dispatcher =
+                retryUsingImsService
+                        ? mImsSmsDispatcher
+                        : (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher;
 
-        SMSDispatcher dispatcher = (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher;
-
-        tracker.mFormat = dispatcher.getFormat();
         dispatcher.sendSms(tracker);
     }
 
diff --git a/src/java/com/android/internal/telephony/SmsPermissions.java b/src/java/com/android/internal/telephony/SmsPermissions.java
index 463ffe7..02ecdf4 100644
--- a/src/java/com/android/internal/telephony/SmsPermissions.java
+++ b/src/java/com/android/internal/telephony/SmsPermissions.java
@@ -17,16 +17,17 @@
 package com.android.internal.telephony;
 
 import android.Manifest;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.service.carrier.CarrierMessagingService;
-import android.telephony.Rlog;
 import android.util.Log;
 
+import com.android.telephony.Rlog;
+
 /**
  * Permissions checks for SMS functionality
  */
@@ -92,11 +93,12 @@
             }
         } catch (PackageManager.NameNotFoundException e) {
             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
-                log("Cannot find configured carrier ims package");
+                loge("Cannot find configured carrier ims package");
             }
         }
 
-        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mPhone.getSubId(), message);
+        TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+                mContext, mPhone.getSubId(), message);
     }
 
     /**
@@ -143,7 +145,7 @@
                         .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
                                 mContext, mPhone.getSubId(), message);
             } catch (SecurityException e) { // To avoid crashing applications
-                Log.e(LOG_TAG, message + ": Neither " + callingPackage + " is the default SMS app"
+                loge(message + ": Neither " + callingPackage + " is the default SMS app"
                         + " nor the caller has "
                         + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
                         + ", or carrier privileges", e);
@@ -171,7 +173,7 @@
                 TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                         mContext, mPhone.getSubId(), message);
             } catch (SecurityException e) { // To avoid crashing applications
-                Log.e(LOG_TAG, message + ": Neither " + callingPackage + " is the default SMS app"
+                loge(message + ": Neither " + callingPackage + " is the default SMS app"
                         + " nor the caller has " + android.Manifest.permission.MODIFY_PHONE_STATE
                         + ", or carrier privileges", e);
                 return false;
@@ -188,6 +190,14 @@
 
     @UnsupportedAppUsage
     protected void log(String msg) {
-        Log.d(LOG_TAG, "[IccSmsInterfaceManager] " + msg);
+        Rlog.d(LOG_TAG, msg);
+    }
+
+    protected void loge(String msg) {
+        Rlog.e(LOG_TAG, msg);
+    }
+
+    protected void loge(String msg, Throwable e) {
+        Rlog.e(LOG_TAG, msg, e);
     }
 }
diff --git a/src/java/com/android/internal/telephony/SmsResponse.java b/src/java/com/android/internal/telephony/SmsResponse.java
index 9ce27bf..e2209be 100644
--- a/src/java/com/android/internal/telephony/SmsResponse.java
+++ b/src/java/com/android/internal/telephony/SmsResponse.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Object returned by the RIL upon successful completion of sendSMS.
diff --git a/src/java/com/android/internal/telephony/SmsStorageMonitor.java b/src/java/com/android/internal/telephony/SmsStorageMonitor.java
index 1dcbdd6..9eb43da 100755
--- a/src/java/com/android/internal/telephony/SmsStorageMonitor.java
+++ b/src/java/com/android/internal/telephony/SmsStorageMonitor.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -26,9 +26,10 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 
+import com.android.telephony.Rlog;
+
 /**
  * Monitors the device and ICC storage, and sends the appropriate events.
  *
diff --git a/src/java/com/android/internal/telephony/SmsUsageMonitor.java b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
index 2107963..28e674b 100644
--- a/src/java/com/android/internal/telephony/SmsUsageMonitor.java
+++ b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
@@ -16,8 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
-import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -27,17 +26,16 @@
 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;
-import android.telephony.Rlog;
 import android.telephony.SmsManager;
 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 com.android.telephony.Rlog;
 
 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 24bb42d..7d6a073 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -22,9 +22,9 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -43,9 +43,9 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.RadioAccessFamily;
-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;
@@ -61,8 +61,9 @@
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.telephony.util.TelephonyUtils;
-import com.android.internal.util.ArrayUtils;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -133,7 +134,6 @@
 
     /** The singleton instance. */
     private static SubscriptionController sInstance = null;
-    protected static Phone[] sPhones;
     @UnsupportedAppUsage
     protected Context mContext;
     protected TelephonyManager mTelephonyManager;
@@ -161,7 +161,9 @@
             SubscriptionManager.WFC_IMS_ROAMING_ENABLED,
             SubscriptionManager.DATA_ROAMING,
             SubscriptionManager.DISPLAY_NAME,
-            SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES));
+            SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES,
+            SubscriptionManager.UICC_APPLICATIONS_ENABLED,
+            SubscriptionManager.IMS_RCS_UCE_ENABLED));
 
     public static SubscriptionController init(Context c) {
         synchronized (SubscriptionController.class) {
@@ -365,6 +367,8 @@
                 SubscriptionManager.SUBSCRIPTION_TYPE));
         String groupOwner = getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER,
                 /*defaultVal*/ null);
+        boolean areUiccApplicationsEnabled = cursor.getInt(cursor.getColumnIndexOrThrow(
+                SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1;
 
         if (VDBG) {
             String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId);
@@ -379,7 +383,8 @@
                     + " cardId:" + cardIdToPrint + " publicCardId:" + publicCardId
                     + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID
                     + " profileClass:" + profileClass + " subscriptionType: " + subType
-                    + " carrierConfigAccessRules:" + carrierConfigAccessRules);
+                    + " carrierConfigAccessRules:" + carrierConfigAccessRules
+                    + " areUiccApplicationsEnabled: " + areUiccApplicationsEnabled);
         }
 
         // If line1number has been set to a different number, use it instead.
@@ -391,7 +396,7 @@
                 carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
                 countryIso, isEmbedded, accessRules, cardId, publicCardId, isOpportunistic,
                 groupUUID, false /* isGroupDisabled */, carrierId, profileClass, subType,
-                groupOwner, carrierConfigAccessRules);
+                groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled);
         info.setAssociatedPlmns(ehplmns, hplmns);
         return info;
     }
@@ -403,6 +408,17 @@
     }
 
     /**
+     * Get a subscription that matches IccId.
+     * @return null if there isn't a match, or subscription info if there is one.
+     */
+    public SubscriptionInfo getSubInfoForIccId(String iccId) {
+        List<SubscriptionInfo> info = getSubInfo(SubscriptionManager.ICC_ID + "=" + iccId, null);
+        if (info == null || info.size() == 0) return null;
+        // Should be at most one subscription with the iccid.
+        return info.get(0);
+    }
+
+    /**
      * Query SubInfoRecord(s) from subinfo database
      * @param selection A filter declaring which rows to return
      * @param queryKey query key content
@@ -444,11 +460,13 @@
     /**
      * Find unused color to be set for new SubInfoRecord
      * @param callingPackage The package making the IPC.
+     * @param callingFeatureId The feature in the package
      * @return RGB integer value of color
      */
-    private int getUnusedColor(String callingPackage) {
-        List<SubscriptionInfo> availableSubInfos = getActiveSubscriptionInfoList(callingPackage);
-        colorArr = mContext.getResources().getIntArray(com.android.internal.R.array.sim_colors);
+    private int getUnusedColor(String callingPackage, String callingFeatureId) {
+        List<SubscriptionInfo> availableSubInfos = getActiveSubscriptionInfoList(callingPackage,
+                callingFeatureId);
+        colorArr = mContext.getResources().getIntArray(android.R.array.simColors);
         int colorIdx = 0;
 
         if (availableSubInfos != null) {
@@ -468,17 +486,24 @@
         return colorArr[colorIdx];
     }
 
+    @Deprecated
+    @UnsupportedAppUsage
+    public SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage) {
+        return getActiveSubscriptionInfo(subId, callingPackage, null);
+    }
+
     /**
      * Get the active SubscriptionInfo with the subId key
      * @param subId The unique SubscriptionInfo key in database
      * @param callingPackage The package making the IPC.
+     * @param callingFeatureId The feature in the package
      * @return SubscriptionInfo, maybe null if its not active
      */
-    @UnsupportedAppUsage
     @Override
-    public SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mContext, subId, callingPackage, "getActiveSubscriptionInfo")) {
+    public SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage,
+            String callingFeatureId) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage,
+                callingFeatureId, "getActiveSubscriptionInfo")) {
             return null;
         }
 
@@ -486,7 +511,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             List<SubscriptionInfo> subList = getActiveSubscriptionInfoList(
-                    mContext.getOpPackageName());
+                    mContext.getOpPackageName(), null);
             if (subList != null) {
                 for (SubscriptionInfo si : subList) {
                     if (si.getSubscriptionId() == subId) {
@@ -530,19 +555,10 @@
      * @return SubscriptionInfo, maybe null if its not active
      */
     @Override
-    public SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId, String callingPackage) {
-        // Query the subscriptions unconditionally, and then check whether the caller has access to
-        // the given subscription.
-        final SubscriptionInfo si = getActiveSubscriptionInfoForIccIdInternal(iccId);
-
-        final int subId = si != null
-                ? si.getSubscriptionId() : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mContext, subId, callingPackage, "getActiveSubscriptionInfoForIccId")) {
-            return null;
-        }
-
-        return si;
+    public SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId, String callingPackage,
+            String callingFeatureId) {
+        enforceReadPrivilegedPhoneState("getActiveSubscriptionInfoForIccId");
+        return getActiveSubscriptionInfoForIccIdInternal(iccId);
     }
 
     /**
@@ -557,7 +573,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             List<SubscriptionInfo> subList = getActiveSubscriptionInfoList(
-                    mContext.getOpPackageName());
+                    mContext.getOpPackageName(), null);
             if (subList != null) {
                 for (SubscriptionInfo si : subList) {
                     if (iccId.equals(si.getIccId())) {
@@ -583,11 +599,12 @@
      * This API does not return details on Remote-SIM subscriptions.
      * @param slotIndex the slot which the subscription is inserted
      * @param callingPackage The package making the IPC.
+     * @param callingFeatureId The feature in the package
      * @return SubscriptionInfo, null for Remote-SIMs or non-active slotIndex.
      */
     @Override
     public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex,
-            String callingPackage) {
+            String callingPackage, String callingFeatureId) {
         Phone phone = PhoneFactory.getPhone(slotIndex);
         if (phone == null) {
             if (DBG) {
@@ -596,7 +613,7 @@
             return null;
         }
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mContext, phone.getSubId(), callingPackage,
+                mContext, phone.getSubId(), callingPackage, callingFeatureId,
                 "getActiveSubscriptionInfoForSimSlotIndex")) {
             return null;
         }
@@ -605,7 +622,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             List<SubscriptionInfo> subList = getActiveSubscriptionInfoList(
-                    mContext.getOpPackageName());
+                    mContext.getOpPackageName(), null);
             if (subList != null) {
                 for (SubscriptionInfo si : subList) {
                     if (si.getSimSlotIndex() == slotIndex) {
@@ -634,19 +651,21 @@
 
     /**
      * @param callingPackage The package making the IPC.
+     * @param callingFeatureId The feature in the package
      * @return List of all SubscriptionInfo records in database,
      * include those that were inserted before, maybe empty but not null.
      * @hide
      */
     @Override
-    public List<SubscriptionInfo> getAllSubInfoList(String callingPackage) {
+    public List<SubscriptionInfo> getAllSubInfoList(String callingPackage,
+            String callingFeatureId) {
         if (VDBG) logd("[getAllSubInfoList]+");
 
         // This API isn't public, so no need to provide a valid subscription ID - we're not worried
         // about carrier-privileged callers not having access.
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                 mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
-                "getAllSubInfoList")) {
+                callingFeatureId, "getAllSubInfoList")) {
             return null;
         }
 
@@ -666,16 +685,25 @@
         }
     }
 
+    @Deprecated
+    @UnsupportedAppUsage
+    public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage) {
+        return getSubscriptionInfoListFromCacheHelper(callingPackage, null,
+                mCacheActiveSubInfoList);
+    }
+
     /**
      * Get the SubInfoRecord(s) of the currently active SIM(s) - which include both local
      * and remote SIMs.
      * @param callingPackage The package making the IPC.
+     * @param callingFeatureId The feature in the package
      * @return Array list of currently inserted SubInfoRecord(s)
      */
-    @UnsupportedAppUsage
     @Override
-    public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage) {
-        return getSubscriptionInfoListFromCacheHelper(callingPackage, mCacheActiveSubInfoList);
+    public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage,
+            String callingFeatureId) {
+        return getSubscriptionInfoListFromCacheHelper(callingPackage, callingFeatureId,
+                mCacheActiveSubInfoList);
     }
 
     /**
@@ -724,16 +752,23 @@
         }
     }
 
+    @Deprecated
+    @UnsupportedAppUsage
+    public int getActiveSubInfoCount(String callingPackage) {
+        return getActiveSubInfoCount(callingPackage, null);
+    }
+
     /**
      * Get the SUB count of active SUB(s)
      * @param callingPackage The package making the IPC.
+     * @param callingFeatureId The feature in the package.
      * @return active SIM count
      */
-    @UnsupportedAppUsage
     @Override
-    public int getActiveSubInfoCount(String callingPackage) {
+    public int getActiveSubInfoCount(String callingPackage, String callingFeatureId) {
         // Let getActiveSubscriptionInfoList perform permission checks / filtering.
-        List<SubscriptionInfo> records = getActiveSubscriptionInfoList(callingPackage);
+        List<SubscriptionInfo> records = getActiveSubscriptionInfoList(callingPackage,
+                callingFeatureId);
         if (records == null) {
             if (VDBG) logd("[getActiveSubInfoCount] records null");
             return 0;
@@ -745,17 +780,18 @@
     /**
      * Get the SUB count of all SUB(s) in SubscriptoinInfo database
      * @param callingPackage The package making the IPC.
+     * @param callingFeatureId The feature in the package
      * @return all SIM count in database, include what was inserted before
      */
     @Override
-    public int getAllSubInfoCount(String callingPackage) {
+    public int getAllSubInfoCount(String callingPackage, String callingFeatureId) {
         if (DBG) logd("[getAllSubInfoCount]+");
 
         // This API isn't public, so no need to provide a valid subscription ID - we're not worried
         // about carrier-privileged callers not having access.
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                 mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
-                "getAllSubInfoCount")) {
+                callingFeatureId, "getAllSubInfoCount")) {
             return 0;
         }
 
@@ -793,12 +829,13 @@
     }
 
     @Override
-    public List<SubscriptionInfo> getAvailableSubscriptionInfoList(String callingPackage) {
+    public List<SubscriptionInfo> getAvailableSubscriptionInfoList(String callingPackage,
+            String callingFeatureId) {
         // This API isn't public, so no need to provide a valid subscription ID - we're not worried
         // about carrier-privileged callers not having access.
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                 mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
-                "getAvailableSubscriptionInfoList")) {
+                callingFeatureId, "getAvailableSubscriptionInfoList")) {
             throw new SecurityException("Need READ_PHONE_STATE to call "
                     + " getAvailableSubscriptionInfoList");
         }
@@ -1185,7 +1222,7 @@
                 }
 
                 // Once the records are loaded, notify DcTracker
-                sPhones[slotIndex].updateDataConnectionTracker();
+                PhoneFactory.getPhone(slotIndex).updateDataConnectionTracker();
 
                 if (DBG) logdl("[addSubInfoRecord]- info size=" + sSlotIndexToSubIds.size());
             }
@@ -1310,7 +1347,7 @@
             int newDefault = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
             SubscriptionInfo info = null;
             final List<SubscriptionInfo> records = getActiveSubscriptionInfoList(
-                    mContext.getOpPackageName());
+                    mContext.getOpPackageName(), null);
             if (!records.isEmpty()) {
                 // yes, we have more subscriptions. pick the first one.
                 // FIXME do we need a policy to figure out which one is to be next default
@@ -1364,7 +1401,7 @@
         ContentResolver resolver = mContext.getContentResolver();
         ContentValues value = new ContentValues();
         value.put(SubscriptionManager.ICC_ID, uniqueId);
-        int color = getUnusedColor(mContext.getOpPackageName());
+        int color = getUnusedColor(mContext.getOpPackageName(), null);
         // default SIM color differs between slots
         value.put(SubscriptionManager.COLOR, color);
         value.put(SubscriptionManager.SIM_SLOT_INDEX, slotIndex);
@@ -1506,30 +1543,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,
+                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);
@@ -1549,6 +1583,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;
                 }
             }
@@ -1568,7 +1606,7 @@
             }
             ContentValues value = new ContentValues(1);
             value.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
-            if (nameSource >= SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE) {
+            if (nameSource >= SubscriptionManager.NAME_SOURCE_DEFAULT) {
                 if (DBG) logd("Set nameSource=" + nameSource);
                 value.put(SubscriptionManager.NAME_SOURCE, nameSource);
             }
@@ -1749,6 +1787,7 @@
             case SubscriptionManager.WFC_IMS_ROAMING_MODE:
             case SubscriptionManager.WFC_IMS_ROAMING_ENABLED:
             case SubscriptionManager.DATA_ROAMING:
+            case SubscriptionManager.IMS_RCS_UCE_ENABLED:
                 values.put(propKey, cursor.getInt(columnIndex));
                 break;
             case SubscriptionManager.DISPLAY_NAME:
@@ -1763,7 +1802,7 @@
     // TODO: replace all updates with this helper method.
     private int updateDatabase(ContentValues value, int subId, boolean updateEntireGroup) {
         List<SubscriptionInfo> infoList = getSubscriptionsInGroup(getGroupUuid(subId),
-                mContext.getOpPackageName());
+                mContext.getOpPackageName(), null);
         if (!updateEntireGroup || infoList == null || infoList.size() == 0) {
             // Only update specified subscriptions.
             return mContext.getContentResolver().update(
@@ -1869,6 +1908,33 @@
     }
 
     /**
+     * Set uicc applications being enabled or disabled.
+     * @param enabled whether uicc applications are enabled or disabled.
+     * @return the number of records updated
+     */
+    public int setUiccApplicationsEnabled(boolean enabled, int subId) {
+        if (DBG) logd("[setUiccApplicationsEnabled]+ enabled:" + enabled + " subId:" + subId);
+
+        ContentValues value = new ContentValues(1);
+        value.put(SubscriptionManager.UICC_APPLICATIONS_ENABLED, enabled);
+
+        int result = mContext.getContentResolver().update(
+                SubscriptionManager.getUriForSubscriptionId(subId), value, null, null);
+
+        // Refresh the Cache of Active Subscription Info List
+        refreshCachedActiveSubscriptionInfoList();
+
+        notifySubscriptionInfoChanged();
+
+        if (isActiveSubId(subId)) {
+            Phone phone = PhoneFactory.getPhone(getPhoneId(subId));
+            phone.enableUiccApplications(enabled, null);
+        }
+
+        return result;
+    }
+
+    /**
      * Get IMSI by subscription ID
      * For active subIds, this will always return the corresponding imsi
      * For inactive subIds, once they are activated once, even if they are deactivated at the time
@@ -2108,8 +2174,7 @@
     @Override
     public int getDefaultSubId() {
         int subId;
-        boolean isVoiceCapable = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
+        boolean isVoiceCapable = mTelephonyManager.isVoiceCapable();
         if (isVoiceCapable) {
             subId = getDefaultVoiceSubId();
             if (VDBG) logdl("[getDefaultSubId] isVoiceCapable subId=" + subId);
@@ -2244,7 +2309,7 @@
             }
 
             ProxyController proxyController = ProxyController.getInstance();
-            int len = sPhones.length;
+            int len = TelephonyManager.from(mContext).getActiveModemCount();
             logdl("[setDefaultDataSubId] num phones=" + len + ", subId=" + subId);
 
             if (SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -2252,7 +2317,7 @@
                 RadioAccessFamily[] rafs = new RadioAccessFamily[len];
                 boolean atLeastOneMatch = false;
                 for (int phoneId = 0; phoneId < len; phoneId++) {
-                    Phone phone = sPhones[phoneId];
+                    Phone phone = PhoneFactory.getPhone(phoneId);
                     int raf;
                     int id = phone.getSubId();
                     if (id == subId) {
@@ -2293,11 +2358,11 @@
     @UnsupportedAppUsage
     private void updateAllDataConnectionTrackers() {
         // Tell Phone Proxies to update data connection tracker
-        int len = sPhones.length;
-        if (DBG) logd("[updateAllDataConnectionTrackers] sPhones.length=" + len);
+        int len = TelephonyManager.from(mContext).getActiveModemCount();
+        if (DBG) logd("[updateAllDataConnectionTrackers] activeModemCount=" + len);
         for (int phoneId = 0; phoneId < len; phoneId++) {
             if (DBG) logd("[updateAllDataConnectionTrackers] phoneId=" + phoneId);
-            sPhones[phoneId].updateDataConnectionTracker();
+            PhoneFactory.getPhone(phoneId).updateDataConnectionTracker();
         }
     }
 
@@ -2370,7 +2435,8 @@
      * Whether a subscription is opportunistic or not.
      */
     public boolean isOpportunistic(int subId) {
-        SubscriptionInfo info = getActiveSubscriptionInfo(subId, mContext.getOpPackageName());
+        SubscriptionInfo info = getActiveSubscriptionInfo(subId, mContext.getOpPackageName(),
+                null);
         return (info != null) && info.isOpportunistic();
     }
 
@@ -2433,10 +2499,6 @@
         }
     }
 
-    public void updatePhonesAvailability(Phone[] phones) {
-        sPhones = phones;
-    }
-
     private synchronized ArrayList<Integer> getActiveSubIdArrayList() {
         // Clone the sub id list so it can't change out from under us while iterating
         List<Entry<Integer, ArrayList<Integer>>> simInfoList =
@@ -2493,9 +2555,9 @@
     }
 
     @Override
-    public boolean isActiveSubId(int subId, String callingPackage) {
+    public boolean isActiveSubId(int subId, String callingPackage, String callingFeatureId) {
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage,
-              "isActiveSubId")) {
+                callingFeatureId, "isActiveSubId")) {
             throw new SecurityException("Requires READ_PHONE_STATE permission.");
         }
         final long identity = Binder.clearCallingIdentity();
@@ -2608,8 +2670,12 @@
             case SubscriptionManager.WFC_IMS_MODE:
             case SubscriptionManager.WFC_IMS_ROAMING_MODE:
             case SubscriptionManager.WFC_IMS_ROAMING_ENABLED:
+            case SubscriptionManager.IMS_RCS_UCE_ENABLED:
                 value.put(propKey, Integer.parseInt(propValue));
                 break;
+            case SubscriptionManager.ALLOWED_NETWORK_TYPES:
+                value.put(propKey, Long.parseLong(propValue));
+                break;
             default:
                 if (DBG) logd("Invalid column name");
                 break;
@@ -2626,9 +2692,10 @@
      * @return Value associated with subId and propKey column in database
      */
     @Override
-    public String getSubscriptionProperty(int subId, String propKey, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mContext, subId, callingPackage, "getSubscriptionProperty")) {
+    public String getSubscriptionProperty(int subId, String propKey, String callingPackage,
+            String callingFeatureId) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage,
+                callingFeatureId, "getSubscriptionProperty")) {
             return null;
         }
 
@@ -2675,12 +2742,11 @@
                         case SubscriptionManager.WFC_IMS_MODE:
                         case SubscriptionManager.WFC_IMS_ROAMING_MODE:
                         case SubscriptionManager.WFC_IMS_ROAMING_ENABLED:
+                        case SubscriptionManager.IMS_RCS_UCE_ENABLED:
                         case SubscriptionManager.IS_OPPORTUNISTIC:
                         case SubscriptionManager.GROUP_UUID:
-                        case SubscriptionManager.WHITE_LISTED_APN_DATA:
-                            resultValue = cursor.getInt(0) + "";
-                            break;
                         case SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES:
+                        case SubscriptionManager.ALLOWED_NETWORK_TYPES:
                             resultValue = cursor.getString(0);
                             break;
                         default:
@@ -2740,7 +2806,7 @@
             pw.println("++++++++++++++++++++++++++++++++");
 
             List<SubscriptionInfo> sirl = getActiveSubscriptionInfoList(
-                    mContext.getOpPackageName());
+                    mContext.getOpPackageName(), null);
             if (sirl != null) {
                 pw.println(" ActiveSubInfoList:");
                 for (SubscriptionInfo entry : sirl) {
@@ -2752,7 +2818,7 @@
             pw.flush();
             pw.println("++++++++++++++++++++++++++++++++");
 
-            sirl = getAllSubInfoList(mContext.getOpPackageName());
+            sirl = getAllSubInfoList(mContext.getOpPackageName(), null);
             if (sirl != null) {
                 pw.println(" AllSubInfoList:");
                 for (SubscriptionInfo entry : sirl) {
@@ -2908,9 +2974,10 @@
     }
 
     @Override
-    public List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage) {
+    public List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage,
+            String callingFeatureId) {
         return getSubscriptionInfoListFromCacheHelper(
-                callingPackage, mCacheOpportunisticSubInfoList);
+                callingPackage, callingFeatureId, mCacheOpportunisticSubInfoList);
     }
 
     /**
@@ -3058,12 +3125,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,
@@ -3259,12 +3320,12 @@
      */
     @Override
     public List<SubscriptionInfo> getSubscriptionsInGroup(ParcelUuid groupUuid,
-            String callingPackage) {
+            String callingPackage, String callingFeatureId) {
         long identity = Binder.clearCallingIdentity();
         List<SubscriptionInfo> subInfoList;
 
         try {
-            subInfoList = getAllSubInfoList(mContext.getOpPackageName());
+            subInfoList = getAllSubInfoList(mContext.getOpPackageName(), null);
             if (groupUuid == null || subInfoList == null || subInfoList.isEmpty()) {
                 return new ArrayList<>();
             }
@@ -3276,7 +3337,7 @@
             if (!groupUuid.equals(info.getGroupUuid())) return false;
             int subId = info.getSubscriptionId();
             return TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId,
-                    callingPackage, "getSubscriptionsInGroup")
+                    callingPackage, callingFeatureId, "getSubscriptionsInGroup")
                     || info.canManageSubscription(mContext, callingPackage);
         }).collect(Collectors.toList());
     }
@@ -3318,8 +3379,11 @@
                         "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())
+                    .getAllSubInfoList(mContext.getOpPackageName(), null)
                     .stream()
                     .filter(subInfo -> subInfo.getSubscriptionId() == subId)
                     .findFirst()
@@ -3330,6 +3394,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 {
@@ -3361,46 +3427,41 @@
         // 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.
+            setUiccApplicationsEnabled(enable, subId);
+            return true;
+        }
     }
 
     private void enableSubscriptionOverEuiccManager(int subId, boolean enable,
@@ -3544,12 +3605,13 @@
     // Helper function of getOpportunisticSubscriptions and getActiveSubscriptionInfoList.
     // They are doing similar things except operating on different cache.
     private List<SubscriptionInfo> getSubscriptionInfoListFromCacheHelper(
-            String callingPackage, List<SubscriptionInfo> cacheSubList) {
+            String callingPackage, String callingFeatureId, List<SubscriptionInfo> cacheSubList) {
         boolean canReadAllPhoneState;
         try {
             canReadAllPhoneState = TelephonyPermissions.checkReadPhoneState(mContext,
                     SubscriptionManager.INVALID_SUBSCRIPTION_ID, Binder.getCallingPid(),
-                    Binder.getCallingUid(), callingPackage, "getSubscriptionInfoList");
+                    Binder.getCallingUid(), callingPackage, callingFeatureId,
+                    "getSubscriptionInfoList");
         } catch (SecurityException e) {
             canReadAllPhoneState = false;
         }
@@ -3566,7 +3628,7 @@
                         try {
                             return TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext,
                                     subscriptionInfo.getSubscriptionId(), callingPackage,
-                                    "getSubscriptionInfoList");
+                                    callingFeatureId, "getSubscriptionInfoList");
                         } catch (SecurityException e) {
                             return false;
                         }
@@ -3685,26 +3747,6 @@
         return true;
     }
 
-    // TODO: This method should belong to Telephony manager like other data enabled settings and
-    // override APIs. Remove this once TelephonyManager API is added.
-    @Override
-    public boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow) {
-        if (DBG) logd("[setAlwaysAllowMmsData]+ alwaysAllow:" + alwaysAllow + " subId:" + subId);
-
-        enforceModifyPhoneState("setAlwaysAllowMmsData");
-
-        // Now that all security checks passes, perform the operation as ourselves.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            validateSubId(subId);
-            Phone phone = PhoneFactory.getPhone(getPhoneId(subId));
-            if (phone == null) return false;
-            return phone.getDataEnabledSettings().setAlwaysAllowMmsData(alwaysAllow);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     /**
      * Set allowing mobile data during voice call.
      *
@@ -3769,4 +3811,20 @@
             Binder.restoreCallingIdentity(token);
         }
     }
+
+    /**
+     * Whether it's supported to disable / re-enable a subscription on a physical (non-euicc) SIM.
+     */
+    @Override
+    public boolean canDisablePhysicalSubscription() {
+        enforceReadPrivilegedPhoneState("canToggleUiccApplicationsEnablement");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Phone phone = PhoneFactory.getDefaultPhone();
+            return phone != null && phone.canDisablePhysicalSubscription();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 793f846..9e859ab 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -18,9 +18,9 @@
 
 import android.Manifest;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.UserSwitchObserver;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -46,7 +46,7 @@
 import android.service.euicc.EuiccService;
 import android.service.euicc.GetEuiccProfileInfoListResult;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
+import android.telephony.RadioAccessFamily;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -63,6 +63,7 @@
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UiccSlot;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -173,7 +174,7 @@
                     mCurrentlyActiveUserId = newUserId;
                     CarrierAppUtils.disableCarrierAppsUntilPrivileged(sContext.getOpPackageName(),
                             mPackageManager, TelephonyManager.getDefault(),
-                            sContext.getContentResolver(), mCurrentlyActiveUserId);
+                            mCurrentlyActiveUserId, sContext);
 
                     if (reply != null) {
                         try {
@@ -190,8 +191,8 @@
             logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage());
         }
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(sContext.getOpPackageName(),
-                mPackageManager, TelephonyManager.getDefault(), sContext.getContentResolver(),
-                mCurrentlyActiveUserId);
+                mPackageManager, TelephonyManager.getDefault(),
+                mCurrentlyActiveUserId, sContext);
     }
 
     /**
@@ -425,11 +426,15 @@
 
     private void handleSimNotReady(int phoneId) {
         logd("handleSimNotReady: phoneId: " + phoneId);
+        boolean isFinalState = false;
 
         IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard();
-        if (iccCard.isEmptyProfile()) {
-            // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
-            // phase, the subscription list is accessible. Treating NOT_READY
+        if (iccCard.isEmptyProfile() || areUiccAppsDisabledOnCard(phoneId)) {
+            isFinalState = true;
+            // ICC_NOT_READY is a terminal state for
+            // 1) It's an empty profile as there's no uicc applications. Or
+            // 2) Its uicc applications are set to be disabled.
+            // At this phase, the subscription list is accessible. Treating NOT_READY
             // as equivalent to ABSENT, once the rest of the system can handle it.
             sIccId[phoneId] = ICCID_STRING_FOR_NO_SIM;
             updateSubscriptionInfoByIccId(phoneId, false /* updateEmbeddedSubs */);
@@ -439,6 +444,20 @@
                 null);
         broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT);
         broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_NOT_READY);
+        if (isFinalState) {
+            updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY);
+        }
+    }
+
+    private boolean areUiccAppsDisabledOnCard(int phoneId) {
+        // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from
+        // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another
+        // handleSimNotReady so this will be evaluated again.
+        UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
+        if (slot == null || slot.getIccId() == null) return false;
+        SubscriptionInfo info = SubscriptionController.getInstance()
+                .getSubInfoForIccId(slot.getIccId());
+        return info != null && !info.areUiccApplicationsEnabled();
     }
 
     private void handleSimLoaded(int phoneId) {
@@ -538,6 +557,18 @@
                     }
 
                     // Set the modem network mode
+                    long allowedNetworkTypes = -1;
+                    try {
+                        allowedNetworkTypes = Long.parseLong(
+                                SubscriptionController.getInstance().getSubscriptionProperty(subId,
+                                        SubscriptionManager.ALLOWED_NETWORK_TYPES));
+                    } catch (NumberFormatException err) {
+                        logd("NumberFormat exception");
+                    }
+
+                    long networkTypeBitMask = RadioAccessFamily.getRafFromNetworkType(networkType);
+                    networkType = RadioAccessFamily.getNetworkTypeFromRaf(
+                            (int) (networkTypeBitMask & allowedNetworkTypes));
                     PhoneFactory.getPhone(phoneId).setPreferredNetworkType(networkType, null);
 
                     // Only support automatic selection mode on SIM change.
@@ -556,7 +587,7 @@
         // Update set of enabled carrier apps now that the privilege rules may have changed.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(sContext.getOpPackageName(),
                 mPackageManager, TelephonyManager.getDefault(),
-                sContext.getContentResolver(), mCurrentlyActiveUserId);
+                mCurrentlyActiveUserId, sContext);
 
         /**
          * The sim loading sequence will be
@@ -820,7 +851,7 @@
             int index =
                     findSubscriptionInfoForIccid(existingSubscriptions, embeddedProfile.getIccid());
             int prevCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
-            int nameSource = SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+            int nameSource = SubscriptionManager.NAME_SOURCE_DEFAULT;
             if (index < 0) {
                 // No existing entry for this ICCID; create an empty one.
                 SubscriptionController.getInstance().insertEmptySubInfoRecord(
diff --git a/src/java/com/android/internal/telephony/SubscriptionMonitor.java b/src/java/com/android/internal/telephony/SubscriptionMonitor.java
deleted file mode 100644
index 33376e1..0000000
--- a/src/java/com/android/internal/telephony/SubscriptionMonitor.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-* Copyright (C) 2015 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 android.content.Context;
-import android.os.Handler;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.RemoteException;
-import android.telephony.Rlog;
-import android.util.LocalLog;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Utility singleton to monitor subscription changes and help people act on them.
- * Uses Registrant model to post messages to handlers.
- *
- */
-public class SubscriptionMonitor {
-
-    private final RegistrantList mSubscriptionsChangedRegistrants[];
-
-    private final SubscriptionController mSubscriptionController;
-    private final Context mContext;
-
-    private final int mPhoneSubId[];
-
-    private final Object mLock = new Object();
-
-    private final static boolean VDBG = true;
-    private final static String LOG_TAG = "SubscriptionMonitor";
-
-    private final static int MAX_LOGLINES = 100;
-    private final LocalLog mLocalLog = new LocalLog(MAX_LOGLINES);
-
-    public SubscriptionMonitor(ITelephonyRegistry tr, Context context,
-            SubscriptionController subscriptionController, int numPhones) {
-        mSubscriptionController = subscriptionController;
-        mContext = context;
-
-        mSubscriptionsChangedRegistrants = new RegistrantList[numPhones];
-        mPhoneSubId = new int[numPhones];
-
-        for (int phoneId = 0; phoneId < numPhones; phoneId++) {
-            mSubscriptionsChangedRegistrants[phoneId] = new RegistrantList();
-            mPhoneSubId[phoneId] = mSubscriptionController.getSubIdUsingPhoneId(phoneId);
-        }
-
-        try {
-            tr.addOnSubscriptionsChangedListener(context.getOpPackageName(),
-                    mSubscriptionsChangedListener);
-        } catch (RemoteException e) {
-        }
-    }
-
-    @VisibleForTesting
-    public SubscriptionMonitor() {
-        mSubscriptionsChangedRegistrants = null;
-        mSubscriptionController = null;
-        mContext = null;
-        mPhoneSubId = null;
-    }
-
-    private final IOnSubscriptionsChangedListener mSubscriptionsChangedListener =
-            new IOnSubscriptionsChangedListener.Stub() {
-        @Override
-        public void onSubscriptionsChanged() {
-            synchronized (mLock) {
-                for (int phoneId = 0; phoneId < mPhoneSubId.length; phoneId++) {
-                    final int newSubId = mSubscriptionController.getSubIdUsingPhoneId(phoneId);
-                    final int oldSubId = mPhoneSubId[phoneId];
-                    if (oldSubId != newSubId) {
-                        log("Phone[" + phoneId + "] subId changed " + oldSubId + "->" + newSubId
-                                + ", " + mSubscriptionsChangedRegistrants[phoneId].size()
-                                + " registrants");
-                        mPhoneSubId[phoneId] = newSubId;
-                        mSubscriptionsChangedRegistrants[phoneId].notifyRegistrants();
-                    }
-                }
-            }
-        }
-    };
-
-    public void registerForSubscriptionChanged(int phoneId, Handler h, int what, Object o) {
-        if (invalidPhoneId(phoneId)) {
-            throw new IllegalArgumentException("Invalid PhoneId");
-        }
-        Registrant r = new Registrant(h, what, o);
-        mSubscriptionsChangedRegistrants[phoneId].add(r);
-        r.notifyRegistrant();
-    }
-
-    public void unregisterForSubscriptionChanged(int phoneId, Handler h) {
-        if (invalidPhoneId(phoneId)) {
-            throw new IllegalArgumentException("Invalid PhoneId");
-        }
-        mSubscriptionsChangedRegistrants[phoneId].remove(h);
-    }
-
-    private boolean invalidPhoneId(int phoneId) {
-        if (phoneId >= 0 && phoneId < mPhoneSubId.length) return false;
-        return true;
-    }
-
-    private void log(String s) {
-        Rlog.d(LOG_TAG, s);
-        mLocalLog.log(s);
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
-        synchronized (mLock) {
-            mLocalLog.dump(fd, printWriter, args);
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/TelephonyCapabilities.java b/src/java/com/android/internal/telephony/TelephonyCapabilities.java
index 70f15dc..f2f7ddc 100644
--- a/src/java/com/android/internal/telephony/TelephonyCapabilities.java
+++ b/src/java/com/android/internal/telephony/TelephonyCapabilities.java
@@ -16,10 +16,9 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
 
-import com.android.internal.telephony.Phone;
+import com.android.telephony.Rlog;
 
 /**
  * Utilities that check if the phone supports specified capabilities.
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index bd9b338..b84a407 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -30,7 +30,6 @@
 import android.system.OsConstants;
 import android.system.StructStatVfs;
 import android.telephony.AccessNetworkConstants.TransportType;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
@@ -46,6 +45,7 @@
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccProfile;
+import com.android.telephony.Rlog;
 
 import dalvik.system.PathClassLoader;
 
@@ -60,8 +60,6 @@
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
-
-
 /**
  * This class has one-line methods to instantiate objects only. The purpose is to make code
  * unit-test friendly and use this class as a way to do dependency injection. Instantiating objects
diff --git a/src/java/com/android/internal/telephony/TelephonyDevController.java b/src/java/com/android/internal/telephony/TelephonyDevController.java
index 3cda417..a467283 100644
--- a/src/java/com/android/internal/telephony/TelephonyDevController.java
+++ b/src/java/com/android/internal/telephony/TelephonyDevController.java
@@ -17,20 +17,14 @@
 package com.android.internal.telephony;
 
 import android.content.res.Resources;
-import com.android.internal.telephony.*;
-import android.telephony.TelephonyManager;
-
 import android.os.AsyncResult;
-import android.telephony.Rlog;
-import java.util.BitSet;
-import java.util.List;
-import java.util.ArrayList;
-import android.text.TextUtils;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.telephony.ServiceState;
+
+import com.android.telephony.Rlog;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * TelephonyDevController - provides a unified view of the
diff --git a/src/java/com/android/internal/telephony/TelephonyResourceUtils.java b/src/java/com/android/internal/telephony/TelephonyResourceUtils.java
new file mode 100644
index 0000000..2253103
--- /dev/null
+++ b/src/java/com/android/internal/telephony/TelephonyResourceUtils.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+
+import com.android.telephony.Rlog;
+
+/**
+ * This class provides utility functions for Telephony Resources
+ */
+public final class TelephonyResourceUtils {
+    public static String TELEPHONY_RESOURCE_PACKAGE = "com.android.telephony.resources";
+    private static final String TAG = "TelephonyResourceUtils";
+
+    /**
+     * Retrieve resource for the telephony resource package.
+     */
+    public static Resources getTelephonyResources(Context context) {
+        try {
+            return context.getPackageManager()
+                    .getResourcesForApplication(TELEPHONY_RESOURCE_PACKAGE);
+        }  catch (PackageManager.NameNotFoundException ex) {
+            Rlog.e(TAG, "No resource package found");
+        }
+        return null;
+    }
+}
diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java
index df3bfb4..b8288ae 100644
--- a/src/java/com/android/internal/telephony/TelephonyTester.java
+++ b/src/java/com/android/internal/telephony/TelephonyTester.java
@@ -22,11 +22,10 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.BadParcelableException;
-import android.os.Build;
 import android.os.Bundle;
 import android.telephony.AccessNetworkConstants;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsConferenceState;
 import android.telephony.ims.ImsExternalCallState;
@@ -38,6 +37,8 @@
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.test.TestConferenceEventPackageParser;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -196,7 +197,7 @@
     TelephonyTester(Phone phone) {
         mPhone = phone;
 
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             IntentFilter filter = new IntentFilter();
 
             filter.addAction(mPhone.getActionDetached());
@@ -224,7 +225,7 @@
     }
 
     void dispose() {
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             mPhone.getContext().unregisterReceiver(mIntentReceiver);
         }
     }
@@ -260,7 +261,7 @@
         }
 
         imsCall.getImsCallSessionListenerProxy().callSessionHandoverFailed(imsCall.getCallSession(),
-                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+                TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_IWLAN,
                 new ImsReasonInfo());
     }
 
@@ -369,12 +370,12 @@
         /*if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_REG_STATE)) {
             ss.setVoiceRegState(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_REG_STATE,
                     ServiceState.STATE_OUT_OF_SERVICE));
-            log("Override voice service state with " + ss.getVoiceRegState());
+            log("Override voice service state with " + ss.getState());
         }
         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_REG_STATE)) {
             ss.setDataRegState(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE,
                     ServiceState.STATE_OUT_OF_SERVICE));
-            log("Override data service state with " + ss.getDataRegState());
+            log("Override data service state with " + ss.getDataRegistrationState());
         }
         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_RAT)) {
             ss.setRilVoiceRadioTechnology(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_RAT,
@@ -455,4 +456,4 @@
             ((ImsPhone) mPhone).notifyPreciseCallStateChanged();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/java/com/android/internal/telephony/TimeServiceHelper.java b/src/java/com/android/internal/telephony/TimeServiceHelper.java
index 00bd3d2..d4ff9ad 100644
--- a/src/java/com/android/internal/telephony/TimeServiceHelper.java
+++ b/src/java/com/android/internal/telephony/TimeServiceHelper.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
 import android.app.timedetector.TimeDetector;
 
 /**
@@ -62,8 +62,8 @@
     /**
      * Suggest the time to the {@link TimeDetector}.
      *
-     * @param phoneTimeSuggestion the suggested time
+     * @param timeSuggestion the suggested time
      */
-    void suggestDeviceTime(PhoneTimeSuggestion phoneTimeSuggestion);
+    void suggestDeviceTime(TelephonyTimeSuggestion timeSuggestion);
 
 }
diff --git a/src/java/com/android/internal/telephony/TimeServiceHelperImpl.java b/src/java/com/android/internal/telephony/TimeServiceHelperImpl.java
index 5064d50..10a96aa 100644
--- a/src/java/com/android/internal/telephony/TimeServiceHelperImpl.java
+++ b/src/java/com/android/internal/telephony/TimeServiceHelperImpl.java
@@ -17,15 +17,13 @@
 package com.android.internal.telephony;
 
 import android.app.AlarmManager;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
 import android.app.timedetector.TimeDetector;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
 import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.SystemProperties;
-import android.os.UserHandle;
 import android.provider.Settings;
 
 /**
@@ -95,14 +93,10 @@
     public void setDeviceTimeZone(String zoneId) {
         AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         alarmManager.setTimeZone(zoneId);
-        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra("time-zone", zoneId);
-        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
     @Override
-    public void suggestDeviceTime(PhoneTimeSuggestion phoneTimeSuggestion) {
-        mTimeDetector.suggestPhoneTime(phoneTimeSuggestion);
+    public void suggestDeviceTime(TelephonyTimeSuggestion timeSuggestion) {
+        mTimeDetector.suggestTelephonyTime(timeSuggestion);
     }
 }
diff --git a/src/java/com/android/internal/telephony/TimeZoneLookupHelper.java b/src/java/com/android/internal/telephony/TimeZoneLookupHelper.java
index de2417b..572b190 100644
--- a/src/java/com/android/internal/telephony/TimeZoneLookupHelper.java
+++ b/src/java/com/android/internal/telephony/TimeZoneLookupHelper.java
@@ -24,10 +24,10 @@
 import android.annotation.Nullable;
 import android.icu.util.TimeZone;
 import android.text.TextUtils;
-
-import libcore.timezone.CountryTimeZones;
-import libcore.timezone.CountryTimeZones.TimeZoneMapping;
-import libcore.timezone.TimeZoneFinder;
+import android.timezone.CountryTimeZones;
+import android.timezone.CountryTimeZones.OffsetResult;
+import android.timezone.CountryTimeZones.TimeZoneMapping;
+import android.timezone.TimeZoneFinder;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -41,65 +41,6 @@
 public class TimeZoneLookupHelper {
 
     /**
-     * The result of looking up a time zone using offset information (and possibly more).
-     */
-    public static final class OffsetResult {
-
-        /** A zone that matches the supplied criteria. See also {@link #mIsOnlyMatch}. */
-        @NonNull
-        private final TimeZone mTimeZone;
-
-        /** True if there is only one matching time zone for the supplied criteria. */
-        private final boolean mIsOnlyMatch;
-
-        public OffsetResult(@NonNull TimeZone timeZone, boolean isOnlyMatch) {
-            mTimeZone = Objects.requireNonNull(timeZone);
-            mIsOnlyMatch = isOnlyMatch;
-        }
-
-        /**
-         * Returns a time zone that matches the supplied criteria.
-         */
-        @NonNull
-        public TimeZone getTimeZone() {
-            return mTimeZone;
-        }
-
-        /**
-         * Returns {@code true} if there is only one matching time zone for the supplied criteria.
-         */
-        public boolean getIsOnlyMatch() {
-            return mIsOnlyMatch;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-            OffsetResult that = (OffsetResult) o;
-            return mIsOnlyMatch == that.mIsOnlyMatch
-                    && mTimeZone.getID().equals(that.mTimeZone.getID());
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mTimeZone, mIsOnlyMatch);
-        }
-
-        @Override
-        public String toString() {
-            return "OffsetResult{"
-                    + "mTimeZone(Id)=" + mTimeZone.getID()
-                    + ", mIsOnlyMatch=" + mIsOnlyMatch
-                    + '}';
-        }
-    }
-
-    /**
      * The result of looking up a time zone using country information.
      */
     public static final class CountryResult {
@@ -192,15 +133,18 @@
         // is DST (if known). NITZ is limited in only being able to express DST offsets in whole
         // hours and the DST info is optional.
         Integer dstAdjustmentMillis = nitzData.getDstAdjustmentMillis();
-        Boolean isDst = dstAdjustmentMillis == null ? null : dstAdjustmentMillis != 0;
-        Integer dstAdjustmentMillisToMatch = null; // Don't try to match the precise DST offset.
-        CountryTimeZones.OffsetResult offsetResult = countryTimeZones.lookupByOffsetWithBias(
-                nitzData.getLocalOffsetMillis(), isDst, dstAdjustmentMillisToMatch,
-                nitzData.getCurrentTimeInMillis(), bias);
-        if (offsetResult == null) {
-            return null;
+        if (dstAdjustmentMillis == null) {
+            return countryTimeZones.lookupByOffsetWithBias(
+                    nitzData.getCurrentTimeInMillis(), bias, nitzData.getLocalOffsetMillis());
+
+        } else {
+            // We don't try to match the exact DST offset given, we just use it to work out if
+            // the country is in DST.
+            boolean isDst = dstAdjustmentMillis != 0;
+            return countryTimeZones.lookupByOffsetWithBias(
+                    nitzData.getCurrentTimeInMillis(), bias,
+                    nitzData.getLocalOffsetMillis(), isDst);
         }
-        return new OffsetResult(offsetResult.mTimeZone, offsetResult.mOneMatch);
     }
 
     /**
@@ -257,7 +201,7 @@
 
         String debugInfo;
         int matchQuality;
-        if (countryTimeZones.getDefaultTimeZoneBoost()) {
+        if (countryTimeZones.isDefaultTimeZoneBoosted()) {
             matchQuality = CountryResult.QUALITY_DEFAULT_BOOSTED;
             debugInfo = "Country default is boosted";
         } else {
@@ -291,15 +235,11 @@
         String countryDefaultId = countryDefaultZone.getID();
         int countryDefaultOffset = countryDefaultZone.getOffset(whenMillis);
         for (TimeZoneMapping timeZoneMapping : effectiveTimeZoneMappings) {
-            if (timeZoneMapping.timeZoneId.equals(countryDefaultId)) {
+            if (timeZoneMapping.getTimeZoneId().equals(countryDefaultId)) {
                 continue;
             }
 
             TimeZone timeZone = timeZoneMapping.getTimeZone();
-            if (timeZone == null) {
-                continue;
-            }
-
             int candidateOffset = timeZone.getOffset(whenMillis);
             if (countryDefaultOffset != candidateOffset) {
                 return true;
@@ -371,7 +311,7 @@
         // be strong consistency across calls.
         synchronized (this) {
             if (mLastCountryTimeZones != null) {
-                if (mLastCountryTimeZones.isForCountryCode(isoCountryCode)) {
+                if (mLastCountryTimeZones.matchesCountryCode(isoCountryCode)) {
                     return mLastCountryTimeZones;
                 }
             }
diff --git a/src/java/com/android/internal/telephony/UUSInfo.java b/src/java/com/android/internal/telephony/UUSInfo.java
index 9ef1893..2b4f674 100644
--- a/src/java/com/android/internal/telephony/UUSInfo.java
+++ b/src/java/com/android/internal/telephony/UUSInfo.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 public class UUSInfo {
 
diff --git a/src/java/com/android/internal/telephony/UiccPhoneBookController.java b/src/java/com/android/internal/telephony/UiccPhoneBookController.java
index 5a4d480..733c445 100644
--- a/src/java/com/android/internal/telephony/UiccPhoneBookController.java
+++ b/src/java/com/android/internal/telephony/UiccPhoneBookController.java
@@ -18,29 +18,23 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.ServiceManager;
-import android.telephony.Rlog;
 
-import com.android.internal.telephony.IIccPhoneBook;
 import com.android.internal.telephony.uicc.AdnRecord;
+import com.android.telephony.Rlog;
 
-import java.lang.ArrayIndexOutOfBoundsException;
-import java.lang.NullPointerException;
 import java.util.List;
 
 public class UiccPhoneBookController extends IIccPhoneBook.Stub {
     private static final String TAG = "UiccPhoneBookController";
-    @UnsupportedAppUsage
-    private Phone[] mPhone;
 
     /* only one UiccPhoneBookController exists */
     @UnsupportedAppUsage
-    public UiccPhoneBookController(Phone[] phone) {
+    public UiccPhoneBookController() {
         if (ServiceManager.getService("simphonebook") == null) {
                ServiceManager.addService("simphonebook", this);
         }
-        mPhone = phone;
     }
 
     @Override
@@ -139,7 +133,7 @@
 
         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
         try {
-            return mPhone[phoneId].getIccPhoneBookInterfaceManager();
+            return PhoneFactory.getPhone(phoneId).getIccPhoneBookInterfaceManager();
         } catch (NullPointerException e) {
             Rlog.e(TAG, "Exception is :"+e.toString()+" For subscription :"+subId );
             e.printStackTrace(); //To print stack trace
diff --git a/src/java/com/android/internal/telephony/WakeLockStateMachine.java b/src/java/com/android/internal/telephony/WakeLockStateMachine.java
index 1bc6298..eab9b8e 100644
--- a/src/java/com/android/internal/telephony/WakeLockStateMachine.java
+++ b/src/java/com/android/internal/telephony/WakeLockStateMachine.java
@@ -16,17 +16,17 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Message;
 import android.os.PowerManager;
-import android.telephony.Rlog;
 
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.telephony.Rlog;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -38,7 +38,7 @@
  * {@link #quit}.
  */
 public abstract class WakeLockStateMachine extends StateMachine {
-    protected static final boolean DBG = Build.IS_DEBUGGABLE;
+    protected static final boolean DBG = TelephonyUtils.IS_DEBUGGABLE;
 
     private final PowerManager.WakeLock mWakeLock;
 
@@ -130,7 +130,7 @@
             switch (msg.what) {
                 default: {
                     String errorText = "processMessage: unhandled message type " + msg.what;
-                    if (Build.IS_DEBUGGABLE) {
+                    if (TelephonyUtils.IS_DEBUGGABLE) {
                         throw new RuntimeException(errorText);
                     } else {
                         loge(errorText);
diff --git a/src/java/com/android/internal/telephony/WapPushOverSms.java b/src/java/com/android/internal/telephony/WapPushOverSms.java
index 776bbb6..3944f77 100755
--- a/src/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/src/java/com/android/internal/telephony/WapPushOverSms.java
@@ -20,10 +20,12 @@
 import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
 import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_READ_ORIG_IND;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentValues;
@@ -31,6 +33,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteException;
@@ -43,13 +47,13 @@
 import android.os.UserManager;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.Rlog;
 import android.telephony.SmsManager;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.telephony.uicc.IccUtils;
+import com.android.telephony.Rlog;
 
 import com.google.android.mms.MmsException;
 import com.google.android.mms.pdu.DeliveryInd;
@@ -61,6 +65,7 @@
 import com.google.android.mms.pdu.ReadOrigInd;
 
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * WAP push handler class.
@@ -110,7 +115,7 @@
 
     private void bindWapPushManagerService(Context context) {
         Intent intent = new Intent(IWapPushManager.class.getName());
-        ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
+        ComponentName comp = resolveSystemService(context.getPackageManager(), intent);
         intent.setComponent(comp);
         if (comp == null || !context.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
             Rlog.e(TAG, "bindService() for wappush manager failed");
@@ -122,6 +127,33 @@
         }
     }
 
+    /**
+     * Special function for use by the system to resolve service
+     * intents to system apps.  Throws an exception if there are
+     * multiple potential matches to the Intent.  Returns null if
+     * there are no matches.
+     */
+    private static @Nullable ComponentName resolveSystemService(@NonNull PackageManager pm,
+            @NonNull Intent intent) {
+        List<ResolveInfo> results = pm.queryIntentServices(
+                intent, PackageManager.MATCH_SYSTEM_ONLY);
+        if (results == null) {
+            return null;
+        }
+        ComponentName comp = null;
+        for (int i = 0; i < results.size(); i++) {
+            ResolveInfo ri = results.get(i);
+            ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName,
+                    ri.serviceInfo.name);
+            if (comp != null) {
+                throw new IllegalStateException("Multiple system services handle " + intent
+                    + ": " + comp + ", " + foundComp);
+            }
+            comp = foundComp;
+        }
+        return comp;
+    }
+
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         mWapPushManager = IWapPushManager.Stub.asInterface(service);
@@ -420,7 +452,7 @@
         }
 
         handler.dispatchIntent(intent, getPermissionForType(result.mimeType),
-                getAppOpsPermissionForIntent(result.mimeType), options, receiver,
+                getAppOpsStringPermissionForIntent(result.mimeType), options, receiver,
                 UserHandle.SYSTEM, subId);
         return Activity.RESULT_OK;
     }
@@ -611,12 +643,17 @@
         return permission;
     }
 
-    public static int getAppOpsPermissionForIntent(String mimeType) {
-        int appOp;
+    /**
+     * Return a appOps String for the given MIME type.
+     * @param mimeType MIME type of the Intent
+     * @return The appOps String
+     */
+    public static String getAppOpsStringPermissionForIntent(String mimeType) {
+        String appOp;
         if (WspTypeDecoder.CONTENT_TYPE_B_MMS.equals(mimeType)) {
-            appOp = AppOpsManager.OP_RECEIVE_MMS;
+            appOp = AppOpsManager.OPSTR_RECEIVE_MMS;
         } else {
-            appOp = AppOpsManager.OP_RECEIVE_WAP_PUSH;
+            appOp = AppOpsManager.OPSTR_RECEIVE_WAP_PUSH;
         }
         return appOp;
     }
diff --git a/src/java/com/android/internal/telephony/WspTypeDecoder.java b/src/java/com/android/internal/telephony/WspTypeDecoder.java
index 041db61..372aa73 100755
--- a/src/java/com/android/internal/telephony/WspTypeDecoder.java
+++ b/src/java/com/android/internal/telephony/WspTypeDecoder.java
@@ -16,7 +16,8 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.HashMap;
 
 /**
diff --git a/src/java/com/android/internal/telephony/cat/AppInterface.java b/src/java/com/android/internal/telephony/cat/AppInterface.java
index 4f6ca86..546aefe 100755
--- a/src/java/com/android/internal/telephony/cat/AppInterface.java
+++ b/src/java/com/android/internal/telephony/cat/AppInterface.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 
 /**
diff --git a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java
index 313e56f..936158a 100644
--- a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java
+++ b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -138,10 +138,10 @@
     }
 
     public CatCmdMessage(Parcel in) {
-        mCmdDet = in.readParcelable(null);
-        mTextMsg = in.readParcelable(null);
-        mMenu = in.readParcelable(null);
-        mInput = in.readParcelable(null);
+        mCmdDet = in.readParcelable(CommandDetails.class.getClassLoader());
+        mTextMsg = in.readParcelable(TextMessage.class.getClassLoader());
+        mMenu = in.readParcelable(Menu.class.getClassLoader());
+        mInput = in.readParcelable(Input.class.getClassLoader());
         mLoadIconFailed = (in.readByte() == 1);
         switch (getCmdType()) {
         case LAUNCH_BROWSER:
@@ -150,12 +150,12 @@
             mBrowserSettings.mode = LaunchBrowserMode.values()[in.readInt()];
             break;
         case PLAY_TONE:
-            mToneSettings = in.readParcelable(null);
+            mToneSettings = in.readParcelable(ToneSettings.class.getClassLoader());
             break;
         case SET_UP_CALL:
             mCallSettings = new CallSettings();
-            mCallSettings.confirmMsg = in.readParcelable(null);
-            mCallSettings.callMsg = in.readParcelable(null);
+            mCallSettings.confirmMsg = in.readParcelable(TextMessage.class.getClassLoader());
+            mCallSettings.callMsg = in.readParcelable(TextMessage.class.getClassLoader());
             break;
         case SET_UP_EVENT_LIST:
             mSetupEventListSettings = new SetupEventListSettings();
diff --git a/src/java/com/android/internal/telephony/cat/CatLog.java b/src/java/com/android/internal/telephony/cat/CatLog.java
index 128d7ed..62bdf4e 100644
--- a/src/java/com/android/internal/telephony/cat/CatLog.java
+++ b/src/java/com/android/internal/telephony/cat/CatLog.java
@@ -16,8 +16,9 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
+
+import com.android.telephony.Rlog;
 
 public abstract class CatLog {
     static final boolean DEBUG = true;
diff --git a/src/java/com/android/internal/telephony/cat/CatResponseMessage.java b/src/java/com/android/internal/telephony/cat/CatResponseMessage.java
index a3f2240..e1d4fe3 100644
--- a/src/java/com/android/internal/telephony/cat/CatResponseMessage.java
+++ b/src/java/com/android/internal/telephony/cat/CatResponseMessage.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 public class CatResponseMessage {
         CommandDetails mCmdDet = null;
diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java
index f149c6f..097caa4 100644
--- a/src/java/com/android/internal/telephony/cat/CatService.java
+++ b/src/java/com/android/internal/telephony/cat/CatService.java
@@ -20,10 +20,11 @@
 import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
 import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.USER_ACTIVITY_EVENT;
 
-import android.annotation.UnsupportedAppUsage;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.backup.BackupManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -540,7 +541,7 @@
 
     private void broadcastCatCmdIntent(CatCmdMessage cmdMsg) {
         Intent intent = new Intent(AppInterface.CAT_CMD_ACTION);
-        intent.putExtra("STK CMD", cmdMsg);
+        intent.putExtra( "STK CMD", cmdMsg);
         intent.putExtra("SLOT_ID", mSlotId);
         intent.setComponent(AppInterface.getDefaultSTKApplication());
         CatLog.d(this, "Sending CmdMsg: " + cmdMsg+ " on slotid:" + mSlotId);
@@ -1182,8 +1183,7 @@
         for (int i = 0; i < defaultLocaleList.size(); i++) {
             locales[i+1] = defaultLocaleList.get(i);
         }
-        config.setLocales(new LocaleList(locales));
-        config.userSetLocale = true;
+        mContext.getSystemService(ActivityManager.class).setDeviceLocales(new LocaleList(locales));
         am.updatePersistentConfiguration(config);
         BackupManager.dataChanged("com.android.providers.settings");
     }
diff --git a/src/java/com/android/internal/telephony/cat/CommandDetails.java b/src/java/com/android/internal/telephony/cat/CommandDetails.java
index d7c511a..51a6dd4 100644
--- a/src/java/com/android/internal/telephony/cat/CommandDetails.java
+++ b/src/java/com/android/internal/telephony/cat/CommandDetails.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,7 +28,7 @@
  * Class for Command Details object of proactive commands from SIM.
  * {@hide}
  */
-class CommandDetails extends ValueObject implements Parcelable {
+public class CommandDetails extends ValueObject implements Parcelable {
     @UnsupportedAppUsage
     public boolean compRequired;
     @UnsupportedAppUsage
diff --git a/src/java/com/android/internal/telephony/cat/CommandParams.java b/src/java/com/android/internal/telephony/cat/CommandParams.java
index 80e5973..111f0cd 100755
--- a/src/java/com/android/internal/telephony/cat/CommandParams.java
+++ b/src/java/com/android/internal/telephony/cat/CommandParams.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 
 /**
diff --git a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java
index bafb8bb..d7631ae 100644
--- a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java
+++ b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java
@@ -16,7 +16,13 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.BROWSER_TERMINATION_EVENT;
+import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.BROWSING_STATUS_EVENT;
+import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
+import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
+import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.USER_ACTIVITY_EVENT;
+
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.os.Handler;
 import android.os.Message;
@@ -28,17 +34,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-
-import static com.android.internal.telephony.cat.CatCmdMessage
-                   .SetupEventListConstants.BROWSER_TERMINATION_EVENT;
-import static com.android.internal.telephony.cat.CatCmdMessage
-                   .SetupEventListConstants.BROWSING_STATUS_EVENT;
-import static com.android.internal.telephony.cat.CatCmdMessage
-                   .SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
-import static com.android.internal.telephony.cat.CatCmdMessage
-                   .SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
-import static com.android.internal.telephony.cat.CatCmdMessage
-                   .SetupEventListConstants.USER_ACTIVITY_EVENT;
 /**
  * Factory class, used for decoding raw byte arrays, received from baseband,
  * into a CommandParams object.
diff --git a/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java b/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java
index 16615a0..3651a40 100644
--- a/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java
+++ b/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java
@@ -16,13 +16,13 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
+
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.List;
 
-
 /**
  * Class for representing COMPREHENSION-TLV objects.
  *
diff --git a/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java b/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java
index 1ab18a7..f8ba49f 100644
--- a/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java
+++ b/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Enumeration for representing the tag value of COMPREHENSION-TLV objects. If
diff --git a/src/java/com/android/internal/telephony/cat/Duration.java b/src/java/com/android/internal/telephony/cat/Duration.java
index a979c54..412be9a 100644
--- a/src/java/com/android/internal/telephony/cat/Duration.java
+++ b/src/java/com/android/internal/telephony/cat/Duration.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/src/java/com/android/internal/telephony/cat/IconLoader.java b/src/java/com/android/internal/telephony/cat/IconLoader.java
index 4e5b555..94b5348 100644
--- a/src/java/com/android/internal/telephony/cat/IconLoader.java
+++ b/src/java/com/android/internal/telephony/cat/IconLoader.java
@@ -16,9 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import com.android.internal.telephony.uicc.IccFileHandler;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.os.AsyncResult;
@@ -26,6 +24,9 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+
+import com.android.internal.telephony.uicc.IccFileHandler;
+
 import java.util.HashMap;
 
 /**
diff --git a/src/java/com/android/internal/telephony/cat/Input.java b/src/java/com/android/internal/telephony/cat/Input.java
index aaaff43..e9103b8 100644
--- a/src/java/com/android/internal/telephony/cat/Input.java
+++ b/src/java/com/android/internal/telephony/cat/Input.java
@@ -58,7 +58,7 @@
     private Input(Parcel in) {
         text = in.readString();
         defaultText = in.readString();
-        icon = in.readParcelable(null);
+        icon = in.readParcelable(Bitmap.class.getClassLoader());
         minLen = in.readInt();
         maxLen = in.readInt();
         ucs2 = in.readInt() == 1 ? true : false;
diff --git a/src/java/com/android/internal/telephony/cat/Item.java b/src/java/com/android/internal/telephony/cat/Item.java
index 456a46f..702ed4b 100644
--- a/src/java/com/android/internal/telephony/cat/Item.java
+++ b/src/java/com/android/internal/telephony/cat/Item.java
@@ -46,7 +46,7 @@
     public Item(Parcel in) {
         id = in.readInt();
         text = in.readString();
-        icon = in.readParcelable(null);
+        icon = in.readParcelable(Bitmap.class.getClassLoader());
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/cat/Menu.java b/src/java/com/android/internal/telephony/cat/Menu.java
index a93fd1f..7606007 100644
--- a/src/java/com/android/internal/telephony/cat/Menu.java
+++ b/src/java/com/android/internal/telephony/cat/Menu.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -58,12 +58,12 @@
 
     private Menu(Parcel in) {
         title = in.readString();
-        titleIcon = in.readParcelable(null);
+        titleIcon = in.readParcelable(Bitmap.class.getClassLoader());
         // rebuild items list.
         items = new ArrayList<Item>();
         int size = in.readInt();
         for (int i=0; i<size; i++) {
-            Item item = in.readParcelable(null);
+            Item item = in.readParcelable(Item.class.getClassLoader());
             items.add(item);
         }
         defaultItem = in.readInt();
diff --git a/src/java/com/android/internal/telephony/cat/ResponseData.java b/src/java/com/android/internal/telephony/cat/ResponseData.java
index 4d0a2d2..8c7f248 100644
--- a/src/java/com/android/internal/telephony/cat/ResponseData.java
+++ b/src/java/com/android/internal/telephony/cat/ResponseData.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 
diff --git a/src/java/com/android/internal/telephony/cat/ResultCode.java b/src/java/com/android/internal/telephony/cat/ResultCode.java
index adcf53e..dca2999 100644
--- a/src/java/com/android/internal/telephony/cat/ResultCode.java
+++ b/src/java/com/android/internal/telephony/cat/ResultCode.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/src/java/com/android/internal/telephony/cat/ResultException.java b/src/java/com/android/internal/telephony/cat/ResultException.java
index 32acae8..208aa9a 100644
--- a/src/java/com/android/internal/telephony/cat/ResultException.java
+++ b/src/java/com/android/internal/telephony/cat/ResultException.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java b/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java
index eeb9dd4..a068d05 100755
--- a/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java
+++ b/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.Message;
 import android.telephony.SubscriptionManager;
diff --git a/src/java/com/android/internal/telephony/cat/TextMessage.java b/src/java/com/android/internal/telephony/cat/TextMessage.java
index eddca4c..96ecd94 100644
--- a/src/java/com/android/internal/telephony/cat/TextMessage.java
+++ b/src/java/com/android/internal/telephony/cat/TextMessage.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -40,7 +40,7 @@
     private TextMessage(Parcel in) {
         title = in.readString();
         text = in.readString();
-        icon = in.readParcelable(null);
+        icon = in.readParcelable(Bitmap.class.getClassLoader());
         iconSelfExplanatory = in.readInt() == 1 ? true : false;
         isHighPriority = in.readInt() == 1 ? true : false;
         responseNeeded = in.readInt() == 1 ? true : false;
diff --git a/src/java/com/android/internal/telephony/cat/ToneSettings.java b/src/java/com/android/internal/telephony/cat/ToneSettings.java
index 61c1573..4e94ead 100644
--- a/src/java/com/android/internal/telephony/cat/ToneSettings.java
+++ b/src/java/com/android/internal/telephony/cat/ToneSettings.java
@@ -35,8 +35,8 @@
     }
 
     private ToneSettings(Parcel in) {
-        duration = in.readParcelable(null);
-        tone = in.readParcelable(null);
+        duration = in.readParcelable(Duration.class.getClassLoader());
+        tone = in.readParcelable(Tone.class.getClassLoader());
         vibrate = in.readInt() == 1;
     }
 
diff --git a/src/java/com/android/internal/telephony/cat/ValueParser.java b/src/java/com/android/internal/telephony/cat/ValueParser.java
index 03d7f67..2a19904 100644
--- a/src/java/com/android/internal/telephony/cat/ValueParser.java
+++ b/src/java/com/android/internal/telephony/cat/ValueParser.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.cat;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java b/src/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
index d1e0881..79c4d35 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
@@ -16,9 +16,10 @@
 
 package com.android.internal.telephony.cdma;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import com.android.internal.telephony.PhoneConstants;
+import com.android.telephony.Rlog;
 
 /**
  * Represents a Supplementary Service Notification received from the network.
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
index 0608f88..7a6d6f9 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
@@ -20,17 +20,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Resources;
 import android.os.Message;
 import android.os.RemoteCallback;
 import android.os.SystemProperties;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.SmsCbMessage;
-import android.telephony.TelephonyManager;
 import android.telephony.cdma.CdmaSmsCbProgramResults;
 
-import com.android.internal.telephony.CellBroadcastHandler;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.InboundSmsHandler;
 import com.android.internal.telephony.InboundSmsTracker;
@@ -43,6 +39,7 @@
 import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
+import com.android.internal.telephony.util.TelephonyResourceUtils;
 import com.android.internal.util.HexDump;
 
 import java.io.ByteArrayOutputStream;
@@ -57,7 +54,6 @@
 public class CdmaInboundSmsHandler extends InboundSmsHandler {
 
     private final CdmaSMSDispatcher mSmsDispatcher;
-    private final CdmaServiceCategoryProgramHandler mServiceCategoryProgramHandler;
     private static CdmaCbTestBroadcastReceiver sTestBroadcastReceiver;
     private static CdmaScpTestBroadcastReceiver sTestScpBroadcastReceiver;
 
@@ -67,8 +63,7 @@
     // Callback used to process the result of an SCP message
     private RemoteCallback mScpCallback;
 
-    private final boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean(
-            com.android.internal.R.bool.config_duplicate_port_omadm_wappush);
+    private boolean mCheckForDuplicatePortsInOmadmWapPush = false;
 
     // When TEST_MODE is on we allow the test intent to trigger an SMS CB alert
     private static final boolean TEST_MODE = SystemProperties.getInt("ro.debuggable", 0) == 1;
@@ -76,21 +71,19 @@
             + ".TEST_TRIGGER_CELL_BROADCAST";
     private static final String SCP_TEST_ACTION = "com.android.internal.telephony.cdma"
             + ".TEST_TRIGGER_SCP_MESSAGE";
-    private static final String TOGGLE_CB_MODULE = "com.android.internal.telephony.cdma"
-            + ".TOGGLE_CB_MODULE";
 
     /**
      * Create a new inbound SMS handler for CDMA.
      */
     private CdmaInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor,
             Phone phone, CdmaSMSDispatcher smsDispatcher) {
-        super("CdmaInboundSmsHandler", context, storageMonitor, phone,
-                CellBroadcastHandler.makeCellBroadcastHandler(context, phone));
+        super("CdmaInboundSmsHandler", context, storageMonitor, phone);
         mSmsDispatcher = smsDispatcher;
-        mServiceCategoryProgramHandler = CdmaServiceCategoryProgramHandler.makeScpHandler(context,
-                phone.mCi, phone);
-        phone.mCi.setOnNewCdmaSms(getHandler(), EVENT_NEW_SMS, null);
+        mCheckForDuplicatePortsInOmadmWapPush = TelephonyResourceUtils
+                .getTelephonyResources(context).getBoolean(
+                        com.android.telephony.resources.R.bool.config_duplicate_port_omadm_wappush);
 
+        phone.mCi.setOnNewCdmaSms(getHandler(), EVENT_NEW_SMS, null);
         mCellBroadcastServiceManager.enable();
         mScpCallback = new RemoteCallback(result -> {
             if (result == null) {
@@ -150,7 +143,6 @@
                 sTestBroadcastReceiver = new CdmaCbTestBroadcastReceiver();
                 IntentFilter filter = new IntentFilter();
                 filter.addAction(TEST_ACTION);
-                filter.addAction(TOGGLE_CB_MODULE);
                 context.registerReceiver(sTestBroadcastReceiver, filter);
             }
             if (sTestScpBroadcastReceiver == null) {
@@ -168,7 +160,6 @@
     @Override
     protected void onQuitting() {
         mPhone.mCi.unSetOnNewCdmaSms(getHandler());
-        mCellBroadcastHandler.dispose();
 
         if (DBG) log("unregistered for 3GPP2 SMS");
         super.onQuitting();
@@ -209,11 +200,7 @@
         // Handle CMAS emergency broadcast messages.
         if (isBroadcastType) {
             log("Broadcast type message");
-            if (sEnableCbModule) {
-                mCellBroadcastServiceManager.sendCdmaMessageToHandler(sms);
-            } else {
-                legacyDispatchSmsCbMessage(sms);
-            }
+            mCellBroadcastServiceManager.sendCdmaMessageToHandler(sms);
             return Intents.RESULT_SMS_HANDLED;
         }
 
@@ -244,11 +231,7 @@
                 break;
 
             case SmsEnvelope.TELESERVICE_SCPT:
-                if (sEnableCbModule) {
-                    mCellBroadcastServiceManager.sendCdmaScpMessageToHandler(sms, mScpCallback);
-                } else {
-                    mServiceCategoryProgramHandler.dispatchSmsMessage(sms);
-                }
+                mCellBroadcastServiceManager.sendCdmaScpMessageToHandler(sms, mScpCallback);
                 return Intents.RESULT_SMS_HANDLED;
 
             case SmsEnvelope.TELESERVICE_FDEA_WAP:
@@ -283,19 +266,6 @@
         return dispatchNormalMessage(smsb);
     }
 
-    // dispatch an SMS message through the platform
-    private void legacyDispatchSmsCbMessage(SmsMessage sms) {
-        String plmn =
-                TelephonyManager.from(mContext).getNetworkOperatorForPhone(
-                        mPhone.getPhoneId());
-        SmsCbMessage cbMessage = sms.parseBroadcastSms(plmn, mPhone.getPhoneId());
-        if (cbMessage != null) {
-            mCellBroadcastHandler.dispatchSmsMessage(cbMessage);
-        } else {
-            loge("error trying to parse broadcast SMS");
-        }
-    }
-
     /**
      * Send an acknowledge message.
      *
@@ -484,16 +454,11 @@
      * 493925391C81193D48814D3D555120810D3D0D3D3925393C810D3D5539516480B481393D495120810D1539514 \
      * 9053081054925693D390481553951253080D0C4D481413481354D500 \
      * --ei phone_id 0 \
-     *
-     * adb shell am broadcast -a com.android.internal.telephony.cdma.TOGGLE_CB_MODULE
-     *
-     * adb shell am broadcast -a com.android.internal.telephony.cdma.TOGGLE_CB_MODULE \
-     * --ez enable true
      */
     private class CdmaCbTestBroadcastReceiver extends CbTestBroadcastReceiver {
 
         CdmaCbTestBroadcastReceiver() {
-            super(TEST_ACTION, TOGGLE_CB_MODULE);
+            super(TEST_ACTION);
         }
 
         @Override
@@ -521,23 +486,7 @@
             }
 
             SmsMessage sms = new SmsMessage(new CdmaSmsAddress(), envelope);
-            if (sEnableCbModule) {
                 mCellBroadcastServiceManager.sendCdmaMessageToHandler(sms);
-            } else {
-                legacyDispatchSmsCbMessage(sms);
-            }
-        }
-
-        @Override
-        protected void handleToggleEnable() {
-            // sEnableCbModule is already toggled in super class
-            mCellBroadcastServiceManager.enable();
-        }
-
-        @Override
-        protected void handleToggleDisable(Context context) {
-            // sEnableCbModule is already toggled in super class
-            mCellBroadcastServiceManager.disable();
         }
     }
 
@@ -549,13 +498,11 @@
      * --es originating_address_string 1234567890 \
      * --es bearer_data_string 00031007B0122610880080B2091C5F1D3965DB95054D1CB2E1E883A6F41334E \
      * 6CA830EEC882872DFC32F2E9E40
-     *
-     * To toggle use the CDMA CB test broadcast receiver.
      */
     private class CdmaScpTestBroadcastReceiver extends CbTestBroadcastReceiver {
 
         CdmaScpTestBroadcastReceiver() {
-            super(SCP_TEST_ACTION, null);
+            super(SCP_TEST_ACTION);
         }
 
         @Override
@@ -584,21 +531,7 @@
             }
             SmsMessage sms = new SmsMessage(origAddr, envelope);
             sms.parseSms();
-            if (sEnableCbModule) {
-                mCellBroadcastServiceManager.sendCdmaScpMessageToHandler(sms, mScpCallback);
-            } else {
-                mServiceCategoryProgramHandler.dispatchSmsMessage(sms);
-            }
-        }
-
-        @Override
-        protected void handleToggleEnable() {
-            // noop
-        }
-
-        @Override
-        protected void handleToggleDisable(Context context) {
-            // noop
+            mCellBroadcastServiceManager.sendCdmaScpMessageToHandler(sms, mScpCallback);
         }
     }
 }
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java b/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
index 7600c1a..7a42b00 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
@@ -16,24 +16,23 @@
 
 package com.android.internal.telephony.cdma;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.GsmCdmaPhone;
-import com.android.internal.telephony.uicc.UiccCardApplication;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
-import com.android.internal.telephony.MmiCode;
-import com.android.internal.telephony.Phone;
-
-import android.annotation.UnsupportedAppUsage;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.os.ResultReceiver;
-import android.telephony.Rlog;
 
-import java.util.regex.Pattern;
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.GsmCdmaPhone;
+import com.android.internal.telephony.MmiCode;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
+import com.android.internal.telephony.uicc.UiccCardApplication;
+import com.android.telephony.Rlog;
+
 import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * This class can handle Puk code Mmi
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
old mode 100755
new mode 100644
index 61aa089..3e60612
--- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -18,24 +18,23 @@
 
 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Message;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.Pair;
 
+import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.GsmCdmaPhone;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.SMSDispatcher;
+import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.SmsDispatchersController;
 import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.util.SMSDispatcherUtil;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.SmsMessageBase;
-
+import com.android.internal.telephony.util.SMSDispatcherUtil;
+import com.android.telephony.Rlog;
 
 public class CdmaSMSDispatcher extends SMSDispatcher {
     private static final String TAG = "CdmaSMSDispatcher";
@@ -147,11 +146,13 @@
 
         int currentDataNetwork = mPhone.getServiceState().getDataNetworkType();
         boolean imsSmsDisabled = (currentDataNetwork == TelephonyManager.NETWORK_TYPE_EHRPD
-                    || (ServiceState.isLte(currentDataNetwork)
-                    && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()))
-                    && mPhone.getServiceState().getVoiceNetworkType()
-                    == TelephonyManager.NETWORK_TYPE_1xRTT
-                    && ((GsmCdmaPhone) mPhone).mCT.mState != PhoneConstants.State.IDLE;
+                || (currentDataNetwork == TelephonyManager.NETWORK_TYPE_LTE
+                || currentDataNetwork == TelephonyManager.NETWORK_TYPE_LTE_CA
+                || currentDataNetwork == TelephonyManager.NETWORK_TYPE_NR)
+                && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed())
+                && mPhone.getServiceState().getVoiceNetworkType()
+                        == TelephonyManager.NETWORK_TYPE_1xRTT
+                && ((GsmCdmaPhone) mPhone).mCT.mState != PhoneConstants.State.IDLE;
 
         // sms over cdma is used:
         //   if sms over IMS is not supported AND
@@ -161,7 +162,11 @@
         //   SMS over IMS is being handled by the ImsSmsDispatcher implementation and has indicated
         //   that the message should fall back to sending over CS.
         if (0 == tracker.mImsRetry && !isIms() || imsSmsDisabled || tracker.mUsesImsServiceForIms) {
-            mCi.sendCdmaSms(pdu, reply);
+            if (tracker.mRetryCount == 0 && tracker.mExpectMore) {
+                mCi.sendCdmaSMSExpectMore(pdu,reply);
+            } else {
+                mCi.sendCdmaSms(pdu, reply);
+            }
         } else {
             mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply);
             // increment it here, so in case of SMS_FAIL_RETRY over IMS
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaServiceCategoryProgramHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaServiceCategoryProgramHandler.java
deleted file mode 100644
index 3dc728c..0000000
--- a/src/java/com/android/internal/telephony/cdma/CdmaServiceCategoryProgramHandler.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2013 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.cdma;
-
-import android.Manifest;
-import android.app.Activity;
-import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Message;
-import android.provider.Telephony.Sms.Intents;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.SubscriptionManager;
-import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.cdma.CdmaSmsCbProgramResults;
-
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.WakeLockStateMachine;
-import com.android.internal.telephony.cdma.sms.BearerData;
-import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
-import com.android.internal.telephony.cdma.sms.SmsEnvelope;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * Handle CDMA Service Category Program Data requests and responses.
- */
-public final class CdmaServiceCategoryProgramHandler extends WakeLockStateMachine {
-
-    final CommandsInterface mCi;
-
-    /**
-     * Create a new CDMA inbound SMS handler.
-     */
-    CdmaServiceCategoryProgramHandler(Context context, CommandsInterface commandsInterface,
-            Phone phone) {
-        super("CdmaServiceCategoryProgramHandler", context, phone);
-        mContext = context;
-        mCi = commandsInterface;
-    }
-
-    /**
-     * Create a new State machine for SCPD requests.
-     * @param context the context to use
-     * @param commandsInterface the radio commands interface
-     * @return the new SCPD handler
-     */
-    static CdmaServiceCategoryProgramHandler makeScpHandler(Context context,
-            CommandsInterface commandsInterface, Phone phone) {
-        CdmaServiceCategoryProgramHandler handler = new CdmaServiceCategoryProgramHandler(
-                context, commandsInterface, phone);
-        handler.start();
-        return handler;
-    }
-
-    /**
-     * Handle Cell Broadcast messages from {@code CdmaInboundSmsHandler}.
-     * 3GPP-format Cell Broadcast messages sent from radio are handled in the subclass.
-     *
-     * @param message the message to process
-     * @return true if an ordered broadcast was sent; false on failure
-     */
-    @Override
-    protected boolean handleSmsMessage(Message message) {
-        if (message.obj instanceof SmsMessage) {
-            return handleServiceCategoryProgramData((SmsMessage) message.obj);
-        } else {
-            loge("handleMessage got object of type: " + message.obj.getClass().getName());
-            return false;
-        }
-    }
-
-
-    /**
-     * Send SCPD request to CellBroadcastReceiver as an ordered broadcast.
-     * @param sms the CDMA SmsMessage containing the SCPD request
-     * @return true if an ordered broadcast was sent; false on failure
-     */
-    private boolean handleServiceCategoryProgramData(SmsMessage sms) {
-        ArrayList<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData();
-        if (programDataList == null) {
-            loge("handleServiceCategoryProgramData: program data list is null!");
-            return false;
-        }
-
-        Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION);
-        intent.putExtra("sender", sms.getOriginatingAddress());
-        intent.putParcelableArrayListExtra("program_data", programDataList);
-        SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
-
-        String[] pkgs = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_defaultCellBroadcastReceiverPkgs);
-        mReceiverCount.addAndGet(pkgs.length);
-        for (String pkg : pkgs) {
-            intent.setPackage(pkg);
-            mContext.sendOrderedBroadcast(intent, Manifest.permission.RECEIVE_SMS,
-                    AppOpsManager.OP_RECEIVE_SMS, mScpResultsReceiver,
-                    getHandler(), Activity.RESULT_OK, null, null);
-        }
-        return true;
-    }
-
-    /**
-     * Broadcast receiver to handle results of ordered broadcast. Sends the SCPD results
-     * as a reply SMS, then sends a message to state machine to transition to idle.
-     */
-    private final BroadcastReceiver mScpResultsReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            sendScpResults();
-            if (DBG) log("mScpResultsReceiver finished");
-            if (mReceiverCount.decrementAndGet() == 0) {
-                sendMessage(EVENT_BROADCAST_COMPLETE);
-            }
-        }
-
-        private void sendScpResults() {
-            int resultCode = getResultCode();
-            if ((resultCode != Activity.RESULT_OK) && (resultCode != Intents.RESULT_SMS_HANDLED)) {
-                loge("SCP results error: result code = " + resultCode);
-                return;
-            }
-            Bundle extras = getResultExtras(false);
-            if (extras == null) {
-                loge("SCP results error: missing extras");
-                return;
-            }
-            String sender = extras.getString("sender");
-            if (sender == null) {
-                loge("SCP results error: missing sender extra.");
-                return;
-            }
-            ArrayList<CdmaSmsCbProgramResults> results
-                    = extras.getParcelableArrayList("results");
-            if (results == null) {
-                loge("SCP results error: missing results extra.");
-                return;
-            }
-
-            BearerData bData = new BearerData();
-            bData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
-            bData.messageId = SmsMessage.getNextMessageId();
-            bData.serviceCategoryProgramResults = results;
-            byte[] encodedBearerData = BearerData.encode(bData);
-
-            ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
-            DataOutputStream dos = new DataOutputStream(baos);
-            try {
-                dos.writeInt(SmsEnvelope.TELESERVICE_SCPT);
-                dos.writeInt(0); //servicePresent
-                dos.writeInt(0); //serviceCategory
-                CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
-                        PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(sender));
-                dos.write(destAddr.digitMode);
-                dos.write(destAddr.numberMode);
-                dos.write(destAddr.ton); // number_type
-                dos.write(destAddr.numberPlan);
-                dos.write(destAddr.numberOfDigits);
-                dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
-                // Subaddress is not supported.
-                dos.write(0); //subaddressType
-                dos.write(0); //subaddr_odd
-                dos.write(0); //subaddr_nbr_of_digits
-                dos.write(encodedBearerData.length);
-                dos.write(encodedBearerData, 0, encodedBearerData.length);
-                // Ignore the RIL response. TODO: implement retry if SMS send fails.
-                mCi.sendCdmaSms(baos.toByteArray(), null);
-            } catch (IOException e) {
-                loge("exception creating SCP results PDU", e);
-            } finally {
-                try {
-                    dos.close();
-                } catch (IOException ignored) {
-                }
-            }
-        }
-    };
-}
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSubscriptionSourceManager.java b/src/java/com/android/internal/telephony/cdma/CdmaSubscriptionSourceManager.java
index bc09e77..b261dc5 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaSubscriptionSourceManager.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSubscriptionSourceManager.java
@@ -16,11 +16,7 @@
 
 package com.android.internal.telephony.cdma;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
-import android.annotation.UnsupportedAppUsage;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.Phone;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
@@ -28,7 +24,12 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.provider.Settings;
-import android.telephony.Rlog;
+
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+import com.android.telephony.Rlog;
+
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Class that handles the CDMA subscription source changed events from RIL
diff --git a/src/java/com/android/internal/telephony/cdma/EriManager.java b/src/java/com/android/internal/telephony/cdma/EriManager.java
index eb19963..8c67149 100644
--- a/src/java/com/android/internal/telephony/cdma/EriManager.java
+++ b/src/java/com/android/internal/telephony/cdma/EriManager.java
@@ -16,18 +16,17 @@
 
 package com.android.internal.telephony.cdma;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.util.Xml;
 
 import com.android.internal.telephony.Phone;
-import com.android.internal.util.XmlUtils;
-
+import com.android.internal.telephony.util.XmlUtils;
+import com.android.telephony.Rlog;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java b/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
index 4ac2dea..84da264 100644
--- a/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
+++ b/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
@@ -17,40 +17,11 @@
 package com.android.internal.telephony.cdma;
 
 import android.hardware.radio.V1_0.CdmaSmsMessage;
-import android.os.Parcel;
-import android.os.SystemProperties;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.telephony.TelephonyManager;
-import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.Rlog;
-import android.util.Log;
-import android.text.TextUtils;
-import android.content.res.Resources;
 
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
 import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
-import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.util.BitwiseInputStream;
-import com.android.internal.util.HexDump;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
 
 /**
  * A Factory class to convert from RIL to Framework SMS
diff --git a/src/java/com/android/internal/telephony/cdnr/CarrierConfigEfData.java b/src/java/com/android/internal/telephony/cdnr/CarrierConfigEfData.java
index b17b492..faa5e1f 100644
--- a/src/java/com/android/internal/telephony/cdnr/CarrierConfigEfData.java
+++ b/src/java/com/android/internal/telephony/cdnr/CarrierConfigEfData.java
@@ -19,12 +19,12 @@
 import android.annotation.NonNull;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccRecords.OperatorPlmnInfo;
 import com.android.internal.telephony.uicc.IccRecords.PlmnNetworkName;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java b/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java
index 87ee39d..dad9985 100644
--- a/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java
+++ b/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java
@@ -32,7 +32,6 @@
 import android.content.res.Resources;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.text.TextUtils;
 import android.util.LocalLog;
@@ -49,6 +48,7 @@
 import com.android.internal.telephony.uicc.RuimRecords;
 import com.android.internal.telephony.uicc.SIMRecords;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -337,7 +337,7 @@
         if (useRootLocale) r.getConfiguration().setLocale(Locale.ROOT);
         String[] wfcSpnFormats = r.getStringArray(com.android.internal.R.array.wfcSpnFormats);
         WfcCarrierNameFormatter wfcFormatter = new WfcCarrierNameFormatter(config, wfcSpnFormats,
-                getServiceState().getVoiceRegState() == ServiceState.STATE_POWER_OFF);
+                getServiceState().getState() == ServiceState.STATE_POWER_OFF);
 
         // Override the spn, data spn, plmn by wifi-calling
         String wfcSpn = wfcFormatter.formatVoiceName(rawCarrierDisplayNameData.getSpn());
@@ -380,7 +380,7 @@
         boolean forceDisplayNoService =
                 mPhone.getServiceStateTracker().shouldForceDisplayNoService() && !isSimReady;
         ServiceState ss = getServiceState();
-        if (ss.getVoiceRegState() == ServiceState.STATE_POWER_OFF
+        if (ss.getState() == ServiceState.STATE_POWER_OFF
                 || forceDisplayNoService || !Phone.isEmergencyCallOnly()) {
             plmn = mContext.getResources().getString(
                     com.android.internal.R.string.lockscreen_carrier_default);
@@ -545,7 +545,7 @@
      * @param ss service state.
      */
     private static int getCombinedRegState(ServiceState ss) {
-        if (ss.getVoiceRegState() != ServiceState.STATE_IN_SERVICE) return ss.getDataRegState();
-        return ss.getVoiceRegState();
+        if (ss.getState() != ServiceState.STATE_IN_SERVICE) return ss.getDataRegistrationState();
+        return ss.getState();
     }
 }
diff --git a/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java b/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
index 78e7138..477e331 100644
--- a/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -34,7 +35,6 @@
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.Annotation.ApnType;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.data.ApnSetting;
 import android.telephony.data.IQualifiedNetworksService;
 import android.telephony.data.IQualifiedNetworksServiceCallback;
@@ -44,6 +44,7 @@
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.util.ArrayList;
@@ -212,8 +213,14 @@
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
-        phone.getContext().registerReceiverAsUser(mConfigChangedReceiver, UserHandle.ALL,
-                intentFilter, null, null);
+        try {
+            Context contextAsUser = phone.getContext().createPackageContextAsUser(
+                phone.getContext().getPackageName(), 0, UserHandle.ALL);
+            contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter,
+                null /* broadcastPermission */, null);
+        } catch (PackageManager.NameNotFoundException e) {
+            Rlog.e(TAG, "Package name not found: " + e.getMessage());
+        }
         sendEmptyMessage(EVENT_BIND_QUALIFIED_NETWORKS_SERVICE);
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index d73c900..e614249 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -16,14 +16,12 @@
 
 package com.android.internal.telephony.dataconnection;
 
-import android.app.PendingIntent;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.net.NetworkConfig;
 import android.net.NetworkRequest;
 import android.os.Message;
 import android.telephony.Annotation.ApnType;
-import android.telephony.Rlog;
 import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
 import android.util.LocalLog;
@@ -36,6 +34,7 @@
 import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType;
 import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -68,8 +67,6 @@
 
     String mReason;
 
-    PendingIntent mReconnectAlarmIntent;
-
     /**
      * user/app requested connection on this APN
      */
@@ -170,22 +167,6 @@
     }
 
     /**
-     * Get the reconnect intent.
-     * @return The reconnect intent
-     */
-    public synchronized PendingIntent getReconnectIntent() {
-        return mReconnectAlarmIntent;
-    }
-
-    /**
-     * Save the reconnect intent which can be used for cancelling later.
-     * @param intent The reconnect intent
-     */
-    public synchronized void setReconnectIntent(PendingIntent intent) {
-        mReconnectAlarmIntent = intent;
-    }
-
-    /**
      * Get the current APN setting.
      * @return APN setting
      */
@@ -610,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/ApnSettingUtils.java b/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java
index 07d5608..d072a68 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java
@@ -20,12 +20,12 @@
 import android.os.PersistableBundle;
 import android.telephony.Annotation.ApnType;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.data.ApnSetting;
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.uicc.IccRecords;
+import com.android.telephony.Rlog;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -83,8 +83,8 @@
      */
     public static boolean mvnoMatches(IccRecords r, int mvnoType, String mvnoMatchData) {
         if (mvnoType == ApnSetting.MVNO_TYPE_SPN) {
-            if ((r.getServiceProviderName() != null)
-                    && r.getServiceProviderName().equalsIgnoreCase(mvnoMatchData)) {
+            String spn = r.getServiceProviderNameWithBrandOverride();
+            if ((spn != null) && spn.equalsIgnoreCase(mvnoMatchData)) {
                 return true;
             }
         } else if (mvnoType == ApnSetting.MVNO_TYPE_IMSI) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
index b7676b7..9392182 100644
--- a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
@@ -22,7 +22,6 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.data.DataCallResponse;
 import android.telephony.data.DataProfile;
@@ -31,6 +30,7 @@
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.telephony.Rlog;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 53337fd..1be255b 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -16,27 +16,28 @@
 
 package com.android.internal.telephony.dataconnection;
 
-import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
-import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
+import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED;
+import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.InetAddresses;
 import android.net.KeepalivePacketData;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
 import android.net.NetworkInfo;
-import android.net.NetworkMisc;
+import android.net.NetworkProvider;
 import android.net.NetworkRequest;
-import android.net.NetworkUtils;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.SocketKeepalive;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.PersistableBundle;
@@ -45,12 +46,11 @@
 import android.provider.Telephony;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.TransportType;
-import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.DataFailureCause;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DataFailCause;
 import android.telephony.NetworkRegistrationInfo;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -76,17 +76,16 @@
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.RetryManager;
 import com.android.internal.telephony.ServiceStateTracker;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType;
 import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
 import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -266,6 +265,7 @@
     private static final String NULL_IP = "0.0.0.0";
     private Object mUserData;
     private int mSubscriptionOverride;
+    private boolean mUnmeteredOverride;
     private int mRilRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
     private int mDataRegState = Integer.MAX_VALUE;
     private NetworkInfo mNetworkInfo;
@@ -320,9 +320,9 @@
     static final int EVENT_REEVALUATE_RESTRICTED_STATE = BASE + 25;
     static final int EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES = BASE + 26;
     static final int EVENT_NR_STATE_CHANGED = BASE + 27;
-
+    static final int EVENT_DATA_CONNECTION_METEREDNESS_CHANGED = BASE + 28;
     private static final int CMD_TO_STRING_COUNT =
-            EVENT_NR_STATE_CHANGED - BASE + 1;
+            EVENT_DATA_CONNECTION_METEREDNESS_CHANGED - BASE + 1;
 
     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
     static {
@@ -360,6 +360,8 @@
                 "EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES";
         sCmdToString[EVENT_NR_STATE_CHANGED - BASE] =
                 "EVENT_NR_STATE_CHANGED";
+        sCmdToString[EVENT_DATA_CONNECTION_METEREDNESS_CHANGED - BASE] =
+                "EVENT_DATA_CONNECTION_METEREDNESS_CHANGED";
     }
     // Convert cmd to string or null if unknown
     static String cmdToString(int cmd) {
@@ -416,7 +418,8 @@
         return getCurrentState() == mDisconnectingState;
     }
 
-    boolean isActive() {
+    @VisibleForTesting
+    public boolean isActive() {
         return getCurrentState() == mActiveState;
     }
 
@@ -590,7 +593,7 @@
         mId = id;
         mCid = -1;
         ServiceState ss = mPhone.getServiceState();
-        mDataRegState = mPhone.getServiceState().getDataRegState();
+        mDataRegState = mPhone.getServiceState().getDataRegistrationState();
         int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
 
         NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
@@ -602,8 +605,6 @@
 
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
                 networkType, NETWORK_TYPE, TelephonyManager.getNetworkTypeName(networkType));
-        mNetworkInfo.setRoaming(ss.getDataRoaming());
-        mNetworkInfo.setIsAvailable(true);
 
         addState(mDefaultState);
             addState(mInactiveState, mDefaultState);
@@ -642,10 +643,13 @@
 
         // Check if we should fake an error.
         if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter  > 0) {
-            DataCallResponse response = new DataCallResponse(
-                    mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause,
-                    mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime, 0, 0, 0, "",
-                    null, null, null, null, PhoneConstants.UNSET_MTU);
+            DataCallResponse response = new DataCallResponse.Builder()
+                    .setCause(mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause)
+                    .setSuggestedRetryTime(
+                            mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime)
+                    .setMtuV4(PhoneConstants.UNSET_MTU)
+                    .setMtuV6(PhoneConstants.UNSET_MTU)
+                    .build();
 
             Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
             AsyncResult.forMessage(msg, response, null);
@@ -707,8 +711,7 @@
             }
 
             linkProperties = dc.getLinkProperties();
-            if (linkProperties == null || CollectionUtils.isEmpty(
-                    linkProperties.getLinkAddresses())) {
+            if (linkProperties == null || linkProperties.getLinkAddresses().isEmpty()) {
                 loge("connect: Can't find link properties of handover data connection. dc="
                         + dc);
                 return DataFailCause.HANDOVER_FAILED;
@@ -741,6 +744,15 @@
     }
 
     /**
+     * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on meteredness
+     * @param isUnmetered whether this DC should be set to unmetered or not
+     */
+    public void onMeterednessChanged(boolean isUnmetered) {
+        mUnmeteredOverride = isUnmetered;
+        sendMessage(obtainMessage(EVENT_DATA_CONNECTION_METEREDNESS_CHANGED));
+    }
+
+    /**
      * TearDown the data connection when the deactivation is complete a Message with
      * msg.what == EVENT_DEACTIVATE_DONE
      *
@@ -909,6 +921,8 @@
         mDcFailCause = DataFailCause.NONE;
         mDisabledApnTypeBitMask = 0;
         mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        mSubscriptionOverride = 0;
+        mUnmeteredOverride = false;
     }
 
     /**
@@ -1196,6 +1210,11 @@
     }
 
     /**
+     * Get the network capabilities for this data connection.
+     *
+     * Note that this method reads fields from mNetworkInfo, so its output is only as fresh
+     * as mNetworkInfo. Call updateNetworkInfoSuspendState before calling this.
+     *
      * @return the {@link NetworkCapabilities} of this data connection.
      */
     public NetworkCapabilities getNetworkCapabilities() {
@@ -1264,6 +1283,10 @@
                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX);
                         break;
                     }
+                    case PhoneConstants.APN_TYPE_XCAP: {
+                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
+                        break;
+                    }
                     default:
                 }
             }
@@ -1278,7 +1301,9 @@
                 result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
             }
 
-            result.maybeMarkCapabilitiesRestricted();
+            if (result.deduceRestrictedCapability()) {
+                result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+            }
         }
 
         if (mRestrictedNetworkOverride) {
@@ -1311,7 +1336,8 @@
         result.setLinkUpstreamBandwidthKbps(up);
         result.setLinkDownstreamBandwidthKbps(down);
 
-        result.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(mSubId)));
+        result.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                .setSubscriptionId(mSubId).build());
 
         result.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING,
                 !mPhone.getServiceState().getDataRoaming());
@@ -1319,16 +1345,35 @@
         result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
 
         // Override values set above when requested by policy
-        if ((mSubscriptionOverride & OVERRIDE_UNMETERED) != 0) {
+        if ((mSubscriptionOverride & SUBSCRIPTION_OVERRIDE_UNMETERED) != 0) {
             result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         }
-        if ((mSubscriptionOverride & OVERRIDE_CONGESTED) != 0) {
+        if ((mSubscriptionOverride & SUBSCRIPTION_OVERRIDE_CONGESTED) != 0) {
             result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
         }
 
+        // Override set by DcTracker
+        if (mUnmeteredOverride) {
+            result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        }
+
+        final boolean suspended =
+                mNetworkInfo.getDetailedState() == NetworkInfo.DetailedState.SUSPENDED;
+        result.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED, !suspended);
+
         return result;
     }
 
+    /** @return {@code true} if validation is required, {@code false} otherwise. */
+    public boolean isValidationRequired() {
+        final NetworkCapabilities nc = getNetworkCapabilities();
+        return nc != null
+                && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
+    }
+
     /**
      * @return {@code True} if 464xlat should be skipped.
      */
@@ -1357,7 +1402,11 @@
     public static boolean isIpAddress(String address) {
         if (address == null) return false;
 
-        return InetAddress.isNumeric(address);
+        // Accept IPv6 addresses (only) in square brackets for compatibility.
+        if (address.startsWith("[") && address.endsWith("]") && address.indexOf(':') != -1) {
+            address = address.substring(1, address.length() - 1);
+        }
+        return InetAddresses.isNumericAddress(address);
     }
 
     private SetupResult setLinkProperties(DataCallResponse response,
@@ -1409,7 +1458,7 @@
                         if (dnsAddr.isEmpty()) continue;
                         InetAddress ia;
                         try {
-                            ia = NetworkUtils.numericToInetAddress(dnsAddr);
+                            ia = InetAddresses.parseNumericAddress(dnsAddr);
                         } catch (IllegalArgumentException e) {
                             throw new UnknownHostException("Non-numeric dns addr=" + dnsAddr);
                         }
@@ -1429,13 +1478,17 @@
                 }
 
                 for (InetAddress gateway : response.getGatewayAddresses()) {
+                    int mtu = linkProperties.hasGlobalIpv6Address() ? response.getMtuV6()
+                            : response.getMtuV4();
                     // Allow 0.0.0.0 or :: as a gateway;
                     // this indicates a point-to-point interface.
-                    linkProperties.addRoute(new RouteInfo(gateway));
+                    linkProperties.addRoute(new RouteInfo(null, gateway, null,
+                            RouteInfo.RTN_UNICAST, mtu));
                 }
 
                 // set interface MTU
                 // this may clobber the setting read from the APN db, but that's ok
+                // TODO: remove once LinkProperties#setMtu is deprecated
                 linkProperties.setMtu(response.getMtu());
 
                 result = SetupResult.SUCCESS;
@@ -1595,9 +1648,7 @@
                     AsyncResult ar = (AsyncResult)msg.obj;
                     Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result;
                     mDataRegState = drsRatPair.first;
-                    if (mRilRat != drsRatPair.second) {
-                        updateTcpBufferSizes(drsRatPair.second);
-                    }
+                    updateTcpBufferSizes(drsRatPair.second);
                     mRilRat = drsRatPair.second;
                     if (DBG) {
                         log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
@@ -1615,6 +1666,7 @@
                     break;
                 case EVENT_DATA_CONNECTION_ROAM_ON:
                 case EVENT_DATA_CONNECTION_ROAM_OFF:
+                case EVENT_DATA_CONNECTION_METEREDNESS_CHANGED:
                 case EVENT_DATA_CONNECTION_OVERRIDE_CHANGED:
                     updateNetworkInfo();
                     if (mNetworkAgent != null) {
@@ -1626,7 +1678,7 @@
                 case EVENT_KEEPALIVE_START_REQUEST:
                 case EVENT_KEEPALIVE_STOP_REQUEST:
                     if (mNetworkAgent != null) {
-                        mNetworkAgent.onSocketKeepaliveEvent(
+                        mNetworkAgent.sendSocketKeepaliveEvent(
                                 msg.arg1, SocketKeepalive.ERROR_INVALID_NETWORK);
                     }
                     break;
@@ -1652,7 +1704,6 @@
         }
 
         mNetworkInfo.setSubtype(subtype, TelephonyManager.getNetworkTypeName(subtype));
-        mNetworkInfo.setRoaming(state.getDataRoaming());
     }
 
     private void updateNetworkInfoSuspendState() {
@@ -2006,17 +2057,23 @@
             mNetworkInfo.setExtraInfo(mApnSetting.getApnName());
             updateTcpBufferSizes(mRilRat);
 
-            final NetworkMisc misc = new NetworkMisc();
+            final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder();
             final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent();
-            if (carrierSignalAgent.hasRegisteredReceivers(TelephonyIntents
+            if (carrierSignalAgent.hasRegisteredReceivers(TelephonyManager
                     .ACTION_CARRIER_SIGNAL_REDIRECTED)) {
                 // carrierSignal Receivers will place the carrier-specific provisioning notification
-                misc.provisioningNotificationDisabled = true;
+                configBuilder.disableProvisioningNotification();
             }
-            misc.subscriberId = mPhone.getSubscriberId();
+
+            final String subscriberId = mPhone.getSubscriberId();
+            if (!TextUtils.isEmpty(subscriberId)) {
+                configBuilder.setSubscriberId(subscriberId);
+            }
 
             // set skip464xlat if it is not default otherwise
-            misc.skip464xlat = shouldSkip464Xlat();
+            if (shouldSkip464Xlat()) {
+                configBuilder.disableNat64Detection();
+            }
 
             mUnmeteredUseOnly = isUnmeteredUseOnly();
 
@@ -2068,13 +2125,14 @@
                 mScore = calculateScore();
                 final NetworkFactory factory = PhoneFactory.getNetworkFactory(
                         mPhone.getPhoneId());
-                final int factorySerialNumber = (null == factory)
-                        ? NetworkFactory.SerialNumber.NONE : factory.getSerialNumber();
+                final int providerId = (null == factory)
+                        ? NetworkProvider.ID_NONE : factory.getProviderId();
 
                 mDisabledApnTypeBitMask |= getDisallowedApnTypes();
 
-                mNetworkAgent = DcNetworkAgent.createDcNetworkAgent(DataConnection.this,
-                        mPhone, mNetworkInfo, mScore, misc, factorySerialNumber, mTransportType);
+                mNetworkAgent = new DcNetworkAgent(DataConnection.this,
+                        mPhone, mNetworkInfo, mScore, configBuilder.build(), providerId,
+                        mTransportType);
             }
 
             if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
@@ -2210,6 +2268,7 @@
                 }
                 case EVENT_DATA_CONNECTION_ROAM_ON:
                 case EVENT_DATA_CONNECTION_ROAM_OFF:
+                case EVENT_DATA_CONNECTION_METEREDNESS_CHANGED:
                 case EVENT_DATA_CONNECTION_OVERRIDE_CHANGED: {
                     updateNetworkInfo();
                     if (mNetworkAgent != null) {
@@ -2267,7 +2326,7 @@
                         // so that keepalive requests can be handled (if supported) by the
                         // underlying transport.
                         if (mNetworkAgent != null) {
-                            mNetworkAgent.onSocketKeepaliveEvent(
+                            mNetworkAgent.sendSocketKeepaliveEvent(
                                     msg.arg1, SocketKeepalive.ERROR_INVALID_NETWORK);
                         }
                     }
@@ -2279,7 +2338,8 @@
                     int handle = mNetworkAgent.keepaliveTracker.getHandleForSlot(slotId);
                     if (handle < 0) {
                         loge("No slot found for stopSocketKeepalive! " + slotId);
-                        mNetworkAgent.onSocketKeepaliveEvent(slotId, SocketKeepalive.NO_KEEPALIVE);
+                        mNetworkAgent.sendSocketKeepaliveEvent(
+                                slotId, SocketKeepalive.NO_KEEPALIVE);
                         retVal = HANDLED;
                         break;
                     } else {
@@ -2298,7 +2358,7 @@
                     if (ar.exception != null || ar.result == null) {
                         loge("EVENT_KEEPALIVE_STARTED: error starting keepalive, e="
                                 + ar.exception);
-                        mNetworkAgent.onSocketKeepaliveEvent(
+                        mNetworkAgent.sendSocketKeepaliveEvent(
                                 slot, SocketKeepalive.ERROR_HARDWARE_ERROR);
                     } else {
                         KeepaliveStatus ks = (KeepaliveStatus) ar.result;
@@ -2902,7 +2962,7 @@
         for (ApnContext apnContext : mApnContexts.keySet()) {
             for (NetworkRequest networkRequest : apnContext.getNetworkRequests()) {
                 if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        && networkRequest.networkCapabilities.getNetworkSpecifier() == null) {
+                        && networkRequest.getNetworkSpecifier() == null) {
                     score = DEFAULT_INTERNET_CONNECTION_SCORE;
                     break;
                 }
@@ -2960,6 +3020,7 @@
         pw.println("mSubscriptionOverride=" + Integer.toHexString(mSubscriptionOverride));
         pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride);
         pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly);
+        pw.println("mUnmeteredOverride=" + mUnmeteredOverride);
         pw.println("disallowedApnTypes="
                 + ApnSetting.getApnTypesStringFromBitmask(getDisallowedApnTypes()));
         pw.println("mInstanceNumber=" + mInstanceNumber);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledOverride.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledOverride.java
index ef5b0ca..a8145df 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledOverride.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledOverride.java
@@ -340,7 +340,10 @@
     }
 
     /**
-     * Set allowing mobile data during voice call.
+     * Set allowing mobile data during voice call. This is used for allowing data on the non-default
+     * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will
+     * not be able to use mobile data. By calling this API, data will be temporarily enabled on the
+     * non-default data SIM during the life cycle of the voice call.
      *
      * @param allow {@code true} if allowing using data during voice call, {@code false} if
      * disallowed.
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
index 2b67796..8549e33 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
@@ -27,10 +27,10 @@
 import android.os.RegistrantList;
 import android.os.SystemProperties;
 import android.provider.Settings;
+import android.sysprop.TelephonyProperties;
 import android.telephony.Annotation.CallState;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -42,6 +42,7 @@
 import com.android.internal.telephony.MultiSimSettingController;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.SubscriptionController;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -236,8 +237,7 @@
         // User data should always be true for opportunistic subscription.
         if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext())) return true;
 
-        boolean defaultVal = "true".equalsIgnoreCase(SystemProperties.get(
-                "ro.com.android.mobiledata", "true"));
+        boolean defaultVal = TelephonyProperties.mobile_data().orElse(true);
 
         return GlobalSettingsHelper.getBoolean(mPhone.getContext(),
                 Settings.Global.MOBILE_DATA, mPhone.getSubId(), defaultVal);
@@ -264,16 +264,23 @@
     }
 
     /**
-     * Set allowing mobile data during voice call.
+     * Set allowing mobile data during voice call. This is used for allowing data on the non-default
+     * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will
+     * not be able to use mobile data. By calling this API, data will be temporarily enabled on the
+     * non-default data SIM during the life cycle of the voice call.
      *
      * @param allow {@code true} if allowing using data during voice call, {@code false} if
      * disallowed
      *
-     * @return {@code false} if the setting is changed.
+     * @return {@code true} if operation is successful. otherwise {@code false}.
      */
     public synchronized boolean setAllowDataDuringVoiceCall(boolean allow) {
         localLog("setAllowDataDuringVoiceCall", allow);
+        if (allow == isDataAllowedInVoiceCall()) {
+            return true;
+        }
         mDataEnabledOverride.setDataAllowedInVoiceCall(allow);
+
         boolean changed = SubscriptionController.getInstance()
                 .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules());
         if (changed) {
@@ -448,7 +455,7 @@
 
     private static boolean isStandAloneOpportunistic(int subId, Context context) {
         SubscriptionInfo info = SubscriptionController.getInstance().getActiveSubscriptionInfo(
-                subId, context.getOpPackageName());
+                subId, context.getOpPackageName(), null);
         return (info != null) && info.isOpportunistic() && info.getGroupUuid() == null;
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
index 66d3064..a638e16 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
@@ -43,7 +43,6 @@
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.AnomalyReporter;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.data.DataCallResponse;
 import android.telephony.data.DataProfile;
@@ -55,6 +54,8 @@
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 import java.util.HashSet;
 import java.util.List;
@@ -133,12 +134,12 @@
         final String[] pkgToGrant = {packageName};
         try {
             mPackageManager.grantDefaultPermissionsToEnabledTelephonyDataServices(
-                    pkgToGrant, mPhone.getContext().getUserId());
+                    pkgToGrant, UserHandle.myUserId());
             mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS,
-                mPhone.getContext().getUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED);
+                UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED);
         } catch (RemoteException e) {
             loge("Binder to package manager died, permission grant for DataService failed.");
-            throw e.rethrowAsRuntimeException();
+            throw TelephonyUtils.rethrowAsRuntimeException(e);
         }
     }
 
@@ -157,15 +158,14 @@
             String[] dataServicesArray = new String[dataServices.size()];
             dataServices.toArray(dataServicesArray);
             mPackageManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices(
-                    dataServicesArray, mPhone.getContext().getUserId());
+                    dataServicesArray, UserHandle.myUserId());
             for (String pkg : dataServices) {
-                mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS,
-                        mPhone.getContext().getUserId(),
+                mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, UserHandle.myUserId(),
                         pkg, AppOpsManager.MODE_ERRORED);
             }
         } catch (RemoteException e) {
             loge("Binder to package manager died; failed to revoke DataService permissions.");
-            throw e.rethrowAsRuntimeException();
+            throw TelephonyUtils.rethrowAsRuntimeException(e);
         }
     }
 
@@ -287,7 +287,14 @@
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
-
+        try {
+            Context contextAsUser = phone.getContext().createPackageContextAsUser(
+                    phone.getContext().getPackageName(), 0, UserHandle.ALL);
+            contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter,
+                    null /* broadcastPermission */, null);
+        } catch (PackageManager.NameNotFoundException e) {
+            loge("Package name not found: " + e.getMessage());
+        }
         PhoneConfigurationManager.registerForMultiSimConfigChange(
                 this, EVENT_BIND_DATA_SERVICE, null);
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index ed2bc82..abf9e7b 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -18,27 +18,26 @@
 
 import android.content.Context;
 import android.hardware.radio.V1_4.DataConnActiveStatus;
-import android.net.INetworkPolicyListener;
 import android.net.LinkAddress;
 import android.net.LinkProperties.CompareResult;
-import android.net.NetworkPolicyManager;
 import android.net.NetworkUtils;
 import android.os.AsyncResult;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.DataFailCause;
 import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.telephony.data.DataCallResponse;
 
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult;
+import com.android.internal.telephony.util.HandlerExecutor;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -69,7 +68,6 @@
     private DccDefaultState mDccDefaultState = new DccDefaultState();
 
     final TelephonyManager mTelephonyManager;
-    final NetworkPolicyManager mNetworkPolicyManager;
 
     private PhoneStateListener mPhoneStateListener;
 
@@ -98,7 +96,7 @@
         setInitialState(mDccDefaultState);
         log("X ctor");
 
-        mPhoneStateListener = new PhoneStateListener(handler.getLooper()) {
+        mPhoneStateListener = new PhoneStateListener(new HandlerExecutor(handler)) {
             @Override
             public void onCarrierNetworkChange(boolean active) {
                 mExecutingCarrierChange = active;
@@ -107,10 +105,8 @@
 
         mTelephonyManager = (TelephonyManager) phone.getContext()
                 .getSystemService(Context.TELEPHONY_SERVICE);
-        mNetworkPolicyManager = (NetworkPolicyManager) phone.getContext()
-                .getSystemService(Context.NETWORK_POLICY_SERVICE);
 
-        mDcTesterDeactivateAll = (Build.IS_DEBUGGABLE)
+        mDcTesterDeactivateAll = (TelephonyUtils.IS_DEBUGGABLE)
                 ? new DcTesterDeactivateAll(mPhone, DcController.this, getHandler())
                 : null;
 
@@ -173,21 +169,6 @@
         return mExecutingCarrierChange;
     }
 
-    private final INetworkPolicyListener mListener = new NetworkPolicyManager.Listener() {
-        @Override
-        public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) {
-            if (mPhone == null || mPhone.getSubId() != subId) return;
-
-            final HashMap<Integer, DataConnection> dcListActiveByCid;
-            synchronized (mDcListAll) {
-                dcListActiveByCid = new HashMap<>(mDcListActiveByCid);
-            }
-            for (DataConnection dc : dcListActiveByCid.values()) {
-                dc.onSubscriptionOverride(overrideMask, overrideValue);
-            }
-        }
-    };
-
     private class DccDefaultState extends State {
         @Override
         public void enter() {
@@ -199,10 +180,6 @@
 
             mDataServiceManager.registerForDataCallListChanged(getHandler(),
                     DataConnection.EVENT_DATA_STATE_CHANGED);
-
-            if (mNetworkPolicyManager != null) {
-                mNetworkPolicyManager.registerListener(mListener);
-            }
         }
 
         @Override
@@ -216,9 +193,6 @@
             if (mDcTesterDeactivateAll != null) {
                 mDcTesterDeactivateAll.dispose();
             }
-            if (mNetworkPolicyManager != null) {
-                mNetworkPolicyManager.unregisterListener(mListener);
-            }
         }
 
         @Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
index a68c7b4..420340d 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
@@ -19,7 +19,8 @@
 import android.content.Intent;
 import android.telephony.Annotation.DataFailureCause;
 import android.telephony.DataFailCause;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 /**
  * A package visible class for supporting testing failing bringUp commands. This
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
index 381bc6e..8998686 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
@@ -20,25 +20,25 @@
 import android.net.LinkProperties;
 import android.net.NattKeepalivePacketData;
 import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
-import android.net.NetworkMisc;
 import android.net.SocketKeepalive;
 import android.os.Message;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.TransportType;
-import android.telephony.Rlog;
 import android.util.LocalLog;
 import android.util.SparseArray;
 
 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 com.android.telephony.Rlog;
 
 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,
-                dc.getNetworkCapabilities(), dc.getLinkProperties(), score, misc,
+    DcNetworkAgent(DataConnection dc, Phone phone, NetworkInfo ni, int score,
+            NetworkAgentConfig config, int factorySerialNumber, int transportType) {
+        super(dc.getHandler().getLooper(), phone.getContext(), "DcNetworkAgent", ni,
+                dc.getNetworkCapabilities(), dc.getLinkProperties(), score, config,
                 factorySerialNumber);
-        mTag = tag;
+        mTag = "DcNetworkAgent" + "-" + network.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.
@@ -187,7 +162,7 @@
         DcTracker dct = mPhone.getDcTracker(mTransportType);
         if (dct != null) {
             Message msg = dct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                    status, 0, redirectUrl);
+                    status, mDataConnection.getCid(), redirectUrl);
             msg.sendToTarget();
         }
     }
@@ -216,6 +191,17 @@
                     + ", 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.hasCapability(
+                                NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+                                        != mNetworkCapabilities.hasCapability(
+                                                NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) {
+                    TelephonyMetrics.getInstance().writeNetworkCapabilitiesChangedEvent(
+                            mPhone.getPhoneId(), networkCapabilities);
+                }
+            }
             mNetworkCapabilities = networkCapabilities;
         }
         sendNetworkCapabilities(networkCapabilities);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java
index cda4836..f4b26b6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java
@@ -20,11 +20,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.os.Build;
 import android.os.Handler;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 /**
  * To bring down all DC's send the following intent:
@@ -69,7 +69,7 @@
         mPhone = phone;
         mDcc = dcc;
 
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             IntentFilter filter = new IntentFilter();
 
             filter.addAction(sActionDcTesterDeactivateAll);
@@ -83,7 +83,7 @@
     }
 
     void dispose() {
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             mPhone.getContext().unregisterReceiver(sIntentReceiver);
         }
     }
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
index 4013454..ba07e12 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
@@ -20,12 +20,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.os.Build;
 import android.os.Handler;
 import android.telephony.DataFailCause;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 /**
  * A package level call that causes all DataConnection bringUp calls to fail a specific
@@ -77,7 +77,7 @@
 
     DcTesterFailBringUpAll(Phone phone, Handler handler) {
         mPhone = phone;
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             IntentFilter filter = new IntentFilter();
 
             filter.addAction(mActionFailBringUp);
@@ -94,7 +94,7 @@
     }
 
     void dispose() {
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             mPhone.getContext().unregisterReceiver(mIntentReceiver);
         }
     }
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index d2354e1..0d2d891 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -19,6 +19,8 @@
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
 import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE;
 import static android.telephony.TelephonyManager.NETWORK_TYPE_NR;
+import static android.telephony.data.ApnSetting.PROTOCOL_IPV4V6;
+import static android.telephony.data.ApnSetting.TYPE_DEFAULT;
 
 import static com.android.internal.telephony.RILConstants.DATA_PROFILE_DEFAULT;
 import static com.android.internal.telephony.RILConstants.DATA_PROFILE_INVALID;
@@ -45,12 +47,12 @@
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
 import android.net.NetworkConfig;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkRequest;
 import android.net.ProxyInfo;
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.os.AsyncResult;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -66,19 +68,20 @@
 import android.provider.Telephony;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.TransportType;
-import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
 import android.telephony.DataFailCause;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PcoData;
-import android.telephony.Rlog;
+import android.telephony.PreciseDataConnectionState;
 import android.telephony.ServiceState;
 import android.telephony.ServiceState.RilRadioTechnology;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.SubscriptionPlan;
 import android.telephony.TelephonyManager;
 import android.telephony.cdma.CdmaCellLocation;
 import android.telephony.data.ApnSetting;
@@ -102,21 +105,23 @@
 import com.android.internal.telephony.PhoneSwitcher;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.SettingsObserver;
-import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
 import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason;
 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.telephony.util.TelephonyUtils;
 import com.android.internal.util.AsyncChannel;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
@@ -128,6 +133,7 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+
 /**
  * {@hide}
  */
@@ -153,8 +159,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,
@@ -254,14 +261,6 @@
     private static final boolean DATA_STALL_SUSPECTED = true;
     private static final boolean DATA_STALL_NOT_SUSPECTED = false;
 
-    private static final String INTENT_RECONNECT_ALARM =
-            "com.android.internal.telephony.data-reconnect";
-    private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
-    private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
-            "reconnect_alarm_extra_reason";
-    private static final String INTENT_RECONNECT_ALARM_EXTRA_TRANSPORT_TYPE =
-            "reconnect_alarm_extra_transport_type";
-
     private static final String INTENT_DATA_STALL_ALARM =
             "com.android.internal.telephony.data-stall";
     // Tag for tracking stale alarms
@@ -340,6 +339,20 @@
     private final LocalLog mDataRoamingLeakageLog = new LocalLog(50);
     private final LocalLog mApnSettingsInitializationLog = new LocalLog(50);
 
+    /* Default for 5G connection reevaluation alarm durations */
+    private long mHysteresisTimeMs = 0;
+    private long mWatchdogTimeMs = 1000 * 60 * 60;
+
+    /* Used to check whether 5G timers are currently active and waiting to go off */
+    private boolean mHysteresis = false;
+    private boolean mWatchdog = false;
+
+    /* List of SubscriptionPlans, updated on SubscriptionManager.setSubscriptionPlans */
+    private List<SubscriptionPlan> mSubscriptionPlans = null;
+
+    /* Used to check whether phone was recently connected to 5G. */
+    private boolean m5GWasConnected = false;
+
     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -358,8 +371,6 @@
                 stopNetStatPoll();
                 startNetStatPoll();
                 restartDataStallAlarm();
-            } else if (action.startsWith(INTENT_RECONNECT_ALARM)) {
-                onActionIntentReconnectAlarm(intent);
             } else if (action.equals(INTENT_DATA_STALL_ALARM)) {
                 onActionIntentDataStallAlarm(intent);
             } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) {
@@ -370,6 +381,17 @@
                 if (mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded()) {
                     setDefaultDataRoamingEnabled();
                 }
+                CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
+                        .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+                if (configManager != null) {
+                    PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
+                    if (b != null) {
+                        mHysteresisTimeMs = b.getLong(
+                                CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT);
+                        mWatchdogTimeMs = b.getLong(
+                                CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG);
+                    }
+                }
             } else {
                 if (DBG) log("onReceive: Unknown action=" + action);
             }
@@ -423,6 +445,27 @@
         }
     };
 
+    private NetworkPolicyManager mNetworkPolicyManager;
+    private final NetworkPolicyManager.SubscriptionCallback mSubscriptionCallback =
+            new NetworkPolicyManager.SubscriptionCallback() {
+        @Override
+        public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) {
+            if (mPhone == null || mPhone.getSubId() != subId) return;
+
+            for (DataConnection dataConnection : mDataConnections.values()) {
+                dataConnection.onSubscriptionOverride(overrideMask, overrideValue);
+            }
+        }
+
+        @Override
+        public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) {
+            if (mPhone == null || mPhone.getSubId() != subId) return;
+
+            mSubscriptionPlans = plans == null ? null : Arrays.asList(plans);
+            reevaluateUnmeteredConnections();
+        }
+    };
+
     private final SettingsObserver mSettingsObserver;
 
     private void registerSettingsObserver() {
@@ -475,14 +518,6 @@
         }
 
         /**
-         * Get Tcp Tx/Rx packet count from TrafficStats
-         */
-        public void updateTcpTxRxSum() {
-            this.txPkts = TrafficStats.getMobileTcpTxPackets();
-            this.rxPkts = TrafficStats.getMobileTcpRxPackets();
-        }
-
-        /**
          * Get total Tx/Rx packet count from TrafficStats
          */
         public void updateTotalTxRxSum() {
@@ -491,28 +526,13 @@
         }
     }
 
-    private void onActionIntentReconnectAlarm(Intent intent) {
-        Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT);
-        msg.setData(intent.getExtras());
-        sendMessage(msg);
-    }
-
-    private void onDataReconnect(Bundle bundle) {
-        String reason = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-        String apnType = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
-
+    private void onDataReconnect(ApnContext apnContextforRetry, int subId) {
         int phoneSubId = mPhone.getSubId();
-        int currSubId = bundle.getInt(PhoneConstants.SUBSCRIPTION_KEY,
-                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        String apnType = apnContextforRetry.getApnType();
+        String reason =  apnContextforRetry.getReason();
 
-        // Stop reconnect if not current subId is not correct.
-        // FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this?
-        if (!SubscriptionManager.isValidSubscriptionId(currSubId) || (currSubId != phoneSubId)) {
-            return;
-        }
-
-        int transportType = bundle.getInt(INTENT_RECONNECT_ALARM_EXTRA_TRANSPORT_TYPE, 0);
-        if (transportType != mTransportType) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != phoneSubId)) {
+            log("onDataReconnect: invalid subId");
             return;
         }
 
@@ -540,8 +560,6 @@
             }
             // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
             sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
-
-            apnContext.setReconnectIntent(null);
         }
     }
 
@@ -652,11 +670,6 @@
 
     //***** Constants
 
-    // Used by puppetmaster/*/radio_stress.py
-    private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active";
-
-    private static final int POLL_PDP_MILLIS = 5 * 1000;
-
     private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000;
 
     static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID =
@@ -734,6 +747,10 @@
         mSubscriptionManager = SubscriptionManager.from(mPhone.getContext());
         mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
 
+        mNetworkPolicyManager = (NetworkPolicyManager) mPhone.getContext()
+                .getSystemService(Context.NETWORK_POLICY_SERVICE);
+        mNetworkPolicyManager.registerSubscriptionCallback(mSubscriptionCallback);
+
         HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");
         dcHandlerThread.start();
         Handler dcHandler = new Handler(dcHandlerThread.getLooper());
@@ -749,13 +766,6 @@
 
         initApnContexts();
 
-        for (ApnContext apnContext : mApnContexts.values()) {
-            // Register the reconnect and restart actions.
-            filter = new IntentFilter();
-            filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType());
-            mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
-        }
-
         initEmergencyApnSetting();
         addEmergencyApnSetting();
 
@@ -795,6 +805,8 @@
                 DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
         mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this,
                 DctConstants.EVENT_DATA_RAT_CHANGED, null);
+        // listens for PhysicalChannelConfig changes
+        mPhone.registerForServiceStateChanged(this, DctConstants.EVENT_SERVICE_STATE_CHANGED, null);
     }
 
     public void unregisterServiceStateTrackerEvents() {
@@ -806,6 +818,7 @@
         mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
         mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType,
                 this);
+        mPhone.unregisterForServiceStateChanged(this);
     }
 
     private void registerForAllEvents() {
@@ -851,6 +864,7 @@
 
         mSubscriptionManager
                 .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
+        mNetworkPolicyManager.unregisterSubscriptionCallback(mSubscriptionCallback);
         mDcc.dispose();
         mDcTesterFailBringUpAll.dispose();
 
@@ -1054,6 +1068,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;
@@ -1106,17 +1123,18 @@
         return result.toArray(new String[0]);
     }
 
+    /** Return active ApnSetting of a specific apnType */
+    public ApnSetting getActiveApnSetting(String apnType) {
+        if (VDBG) log("get active ApnSetting for type:" + apnType);
+        ApnContext apnContext = mApnContexts.get(apnType);
+        return (apnContext != null) ? apnContext.getApnSetting() : null;
+    }
+
     // Return active apn of specific apn type
     public String getActiveApnString(String apnType) {
         if (VDBG) log( "get active apn string for type:" + apnType);
-        ApnContext apnContext = mApnContexts.get(apnType);
-        if (apnContext != null) {
-            ApnSetting apnSetting = apnContext.getApnSetting();
-            if (apnSetting != null) {
-                return apnSetting.getApnName();
-            }
-        }
-        return null;
+        ApnSetting setting = getActiveApnSetting(apnType);
+        return (setting != null) ? setting.getApnName() : null;
     }
 
     /**
@@ -1146,6 +1164,50 @@
         return state;
     }
 
+    /** Convert the internal DctConstants enum state to the TelephonyManager DATA_*  state.
+     * @param state the DctConstants.State
+     * @return a corresponding TelephonyManager.DataState
+     */
+    @TelephonyManager.DataState
+    public static int convertDctStateToTelephonyDataState(DctConstants.State state) {
+        switch(state) {
+            case CONNECTING: // fall through
+            case RETRYING:
+                return TelephonyManager.DATA_CONNECTING;
+            case CONNECTED:
+                return TelephonyManager.DATA_CONNECTED;
+            case DISCONNECTING:
+                return TelephonyManager.DATA_DISCONNECTING;
+            case IDLE: // fall through
+            case FAILED: // fall through
+            default:
+                return TelephonyManager.DATA_DISCONNECTED;
+        }
+    }
+
+    /** Return the Precise Data Connection State information */
+    public @NonNull PreciseDataConnectionState getPreciseDataConnectionState(
+            String apnType, boolean isSuspended, int networkType) {
+
+        int telState = convertDctStateToTelephonyDataState(getState(apnType));
+        // Since suspended isn't actually reported by the DCT, do a fixup based on current
+        // voice call state and device + rat capability
+        if ((telState == TelephonyManager.DATA_CONNECTED
+                || telState == TelephonyManager.DATA_DISCONNECTING)
+                && isSuspended) {
+            telState = TelephonyManager.DATA_SUSPENDED;
+        }
+
+        ApnSetting apnSetting = getActiveApnSetting(apnType);
+        int apnTypesBitmask = ApnSetting.getApnTypesBitmaskFromString(apnType);
+
+        // TODO: should the data fail cause be populated?
+        return new PreciseDataConnectionState(
+                telState, networkType, apnTypesBitmask, apnType,
+                getLinkProperties(apnType),
+                DataFailCause.NONE, apnSetting);
+    }
+
     /**
      * Return a better connection state between {@code stateA} and {@code stateB}. Check
      * {@link #DATA_CONNECTION_STATE_PRIORITIES} for the details.
@@ -1226,7 +1288,7 @@
         if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
         stopNetStatPoll();
         stopDataStallAlarm();
-        mPhone.notifyDataConnection();
+        mPhone.notifyAllActiveDataConnections();
         mAttached.set(false);
     }
 
@@ -1237,7 +1299,7 @@
             if (DBG) log("onDataConnectionAttached: start polling notify attached");
             startNetStatPoll();
             startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
-            mPhone.notifyDataConnection();
+            mPhone.notifyAllActiveDataConnections();
         }
         if (mAutoAttachOnCreationConfig) {
             mAutoAttachEnabled.set(true);
@@ -1518,7 +1580,7 @@
             }
             int radioTech = getDataRat();
             if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN && mPhone.getServiceState()
-                    .getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+                    .getState() == ServiceState.STATE_IN_SERVICE) {
                 radioTech = getVoiceRat();
             }
             log("service state=" + mPhone.getServiceState());
@@ -1528,7 +1590,10 @@
                 ArrayList<ApnSetting> waitingApns =
                         buildWaitingApns(apnContext.getApnType(), radioTech);
                 if (waitingApns.isEmpty()) {
-                    notifyNoData(DataFailCause.MISSING_UNKNOWN_APN, apnContext);
+                    ApnSetting apn = apnContext != null ? apnContext.getApnSetting() : null;
+                    mPhone.notifyDataConnectionFailed(apnContext.getApnType(),
+                            apn != null ? apn.getApnName() : null,
+                            DataFailCause.MISSING_UNKNOWN_APN);
                     String str = "trySetupData: X No APN found retValue=false";
                     if (DBG) log(str);
                     apnContext.requestLog(str);
@@ -1753,7 +1818,7 @@
         // Make sure reconnection alarm is cleaned up if there is no ApnContext
         // associated to the connection.
         if (dataConnection != null) {
-            cancelReconnectAlarm(apnContext);
+            cancelReconnect(apnContext);
         }
         str = "cleanUpConnectionInternal: X detach=" + detach + " reason="
                 + apnContext.getReason();
@@ -1766,10 +1831,6 @@
      */
     @VisibleForTesting
     public @NonNull ArrayList<ApnSetting> fetchDunApns() {
-        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
-            log("fetchDunApns: net.tethering.noprovisioning=true ret: empty list");
-            return new ArrayList<ApnSetting>(0);
-        }
         int bearer = getDataRat();
         ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
         ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
@@ -1856,24 +1917,6 @@
         return null;
     }
 
-    /**
-     * Cancels the alarm associated with apnContext.
-     *
-     * @param apnContext on which the alarm should be stopped.
-     */
-    private void cancelReconnectAlarm(ApnContext apnContext) {
-        if (apnContext == null) return;
-
-        PendingIntent intent = apnContext.getReconnectIntent();
-
-        if (intent != null) {
-                AlarmManager am =
-                    (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
-                am.cancel(intent);
-                apnContext.setReconnectIntent(null);
-        }
-    }
-
     boolean isPermanentFailure(@DataFailureCause int dcFailCause) {
         return (DataFailCause.isPermanentFailure(mPhone.getContext(), dcFailCause,
                 mPhone.getSubId())
@@ -2025,7 +2068,7 @@
             // Search for Initial APN setting and the first apn that can handle default
             for (ApnSetting apn : mAllApnSettings) {
                 if (firstNonEmergencyApnSetting == null
-                        && !apn.canHandleType(ApnSetting.TYPE_EMERGENCY)) {
+                        && !apn.isEmergencyApn()) {
                     firstNonEmergencyApnSetting = apn;
                     log("setInitialApn: firstNonEmergencyApnSetting="
                             + firstNonEmergencyApnSetting);
@@ -2147,8 +2190,8 @@
             }
         }
         boolean onlySingleDcAllowed = false;
-        if (Build.IS_DEBUGGABLE &&
-                SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) {
+        if (TelephonyUtils.IS_DEBUGGABLE
+                && SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) {
             onlySingleDcAllowed = true;
         }
         if (singleDcRats != null) {
@@ -2198,40 +2241,31 @@
         return retry;
     }
 
-    private void startAlarmForReconnect(long delay, ApnContext apnContext) {
-        String apnType = apnContext.getApnType();
-
-        Intent intent = new Intent(INTENT_RECONNECT_ALARM + "." + apnType);
-        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
-        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType);
-        intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TRANSPORT_TYPE, mTransportType);
-        SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
-        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+    private void startReconnect(long delay, ApnContext apnContext) {
+        Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
+                       mPhone.getSubId(), mTransportType, apnContext);
+        cancelReconnect(apnContext);
+        sendMessageDelayed(msg, delay);
 
         if (DBG) {
-            log("startAlarmForReconnect: delay=" + delay + " action=" + intent.getAction()
-                    + " apn=" + apnContext);
+            log("startReconnect: delay=" + delay + " apn="
+                    + apnContext + "reason: " + apnContext.getReason()
+                    + " subId: " + mPhone.getSubId());
         }
-
-        PendingIntent alarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0,
-                                        intent, PendingIntent.FLAG_UPDATE_CURRENT);
-        apnContext.setReconnectIntent(alarmIntent);
-
-        // Use the exact timer instead of the inexact one to provide better user experience.
-        // In some extreme cases, we saw the retry was delayed for few minutes.
-        // Note that if the stated trigger time is in the past, the alarm will be triggered
-        // immediately.
-        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                SystemClock.elapsedRealtime() + delay, alarmIntent);
     }
 
-    private void notifyNoData(@DataFailureCause int lastFailCauseCode,
-                              ApnContext apnContext) {
-        if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
-        if (isPermanentFailure(lastFailCauseCode)
-            && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) {
-            mPhone.notifyDataConnectionFailed(apnContext.getApnType());
+    /**
+     * Cancels the alarm associated with apnContext.
+     *
+     * @param apnContext on which the alarm should be stopped.
+     */
+    private void cancelReconnect(ApnContext apnContext) {
+        if (apnContext == null) return;
+
+        if (DBG) {
+            log("cancelReconnect: apn=" + apnContext);
         }
+        removeMessages(DctConstants.EVENT_DATA_RECONNECT, apnContext);
     }
 
     private void onRecordsLoadedOrSubIdChanged() {
@@ -2245,7 +2279,7 @@
         createAllApnList();
         setDataProfilesAsNeeded();
         setInitialAttachApn();
-        mPhone.notifyDataConnection();
+        mPhone.notifyAllActiveDataConnections();
         setupDataOnAllConnectableApns(Phone.REASON_SIM_LOADED, RetryFailures.ALWAYS);
     }
 
@@ -2572,7 +2606,7 @@
 
             setupDataOnAllConnectableApns(Phone.REASON_ROAMING_OFF, RetryFailures.ALWAYS);
         } else {
-            mPhone.notifyDataConnection();
+            mPhone.notifyAllActiveDataConnections();
         }
     }
 
@@ -2603,7 +2637,7 @@
             if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming");
 
             setupDataOnAllConnectableApns(Phone.REASON_ROAMING_ON, RetryFailures.ALWAYS);
-            mPhone.notifyDataConnection();
+            mPhone.notifyAllActiveDataConnections();
         } else {
             // If the user does not turn on data roaming, when we transit from non-roaming to
             // roaming, we need to tear down the data connection otherwise the user might be
@@ -2635,7 +2669,7 @@
             // Assume data is connected on the simulator
             // FIXME  this can be improved
             // setState(DctConstants.State.CONNECTED);
-            mPhone.notifyDataConnection();
+            mPhone.notifyAllActiveDataConnections();
 
             log("onRadioAvailable: We're on the simulator; assuming data is connected");
         }
@@ -2691,10 +2725,8 @@
                     mProvisioningSpinner));
         }
 
-        // Notify data is connected except for handover case.
-        if (type != REQUEST_TYPE_HANDOVER) {
-            mPhone.notifyDataConnection(apnContext.getApnType());
-        }
+        mPhone.notifyDataConnection(apnContext.getApnType());
+
         startNetStatPoll();
         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
     }
@@ -2750,7 +2782,8 @@
                         if (port == -1) {
                             port = 8080;
                         }
-                        ProxyInfo proxy = new ProxyInfo(apn.getProxyAddressAsString(), port, null);
+                        ProxyInfo proxy = ProxyInfo.buildDirectProxy(
+                                apn.getProxyAddressAsString(), port);
                         dataConnection.setLinkPropertiesHttpProxy(proxy);
                     } catch (NumberFormatException e) {
                         loge("onDataSetupComplete: NumberFormatException making ProxyProperties ("
@@ -2759,24 +2792,12 @@
                 }
 
                 // everything is setup
-                if (TextUtils.equals(apnContext.getApnType(), PhoneConstants.APN_TYPE_DEFAULT)) {
-                    try {
-                        SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true");
-                    } catch (RuntimeException ex) {
-                        log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to true");
-                    }
-                    if (mCanSetPreferApn && mPreferredApn == null) {
-                        if (DBG) log("onDataSetupComplete: PREFERRED APN is null");
-                        mPreferredApn = apn;
-                        if (mPreferredApn != null) {
-                            setPreferredApn(mPreferredApn.getId());
-                        }
-                    }
-                } else {
-                    try {
-                        SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
-                    } catch (RuntimeException ex) {
-                        log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false");
+                if (TextUtils.equals(apnContext.getApnType(), PhoneConstants.APN_TYPE_DEFAULT)
+                        && mCanSetPreferApn && mPreferredApn == null) {
+                    if (DBG) log("onDataSetupComplete: PREFERRED APN is null");
+                    mPreferredApn = apn;
+                    if (mPreferredApn != null) {
+                        setPreferredApn(mPreferredApn.getId());
                     }
                 }
 
@@ -2786,7 +2807,8 @@
                 checkDataRoamingStatus(false);
 
                 boolean isProvApn = apnContext.isProvisioningApn();
-                final ConnectivityManager cm = ConnectivityManager.from(mPhone.getContext());
+                final ConnectivityManager cm = (ConnectivityManager) mPhone.getContext()
+                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                 if (mProvisionBroadcastReceiver != null) {
                     mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver);
                     mProvisionBroadcastReceiver = null;
@@ -2828,7 +2850,7 @@
                 if (DBG) {
                     log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType());
                 }
-                if (Build.IS_DEBUGGABLE) {
+                if (TelephonyUtils.IS_DEBUGGABLE) {
                     // adb shell setprop persist.radio.test.pco [pco_val]
                     String radioTestProperty = "persist.radio.test.pco";
                     int pcoVal = SystemProperties.getInt(radioTestProperty, -1);
@@ -2837,11 +2859,13 @@
                         final byte[] value = new byte[1];
                         value[0] = (byte) pcoVal;
                         final Intent intent =
-                                new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE);
-                        intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, "default");
-                        intent.putExtra(TelephonyIntents.EXTRA_APN_PROTO_KEY, "IPV4V6");
-                        intent.putExtra(TelephonyIntents.EXTRA_PCO_ID_KEY, 0xFF00);
-                        intent.putExtra(TelephonyIntents.EXTRA_PCO_VALUE_KEY, value);
+                                new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE);
+                        intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, "default");
+                        intent.putExtra(TelephonyManager.EXTRA_APN_TYPE_INT, TYPE_DEFAULT);
+                        intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, "IPV4V6");
+                        intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL_INT, PROTOCOL_IPV4V6);
+                        intent.putExtra(TelephonyManager.EXTRA_PCO_ID, 0xFF00);
+                        intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, value);
                         mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
                     }
                 }
@@ -2859,14 +2883,16 @@
                         cause, cid, mTelephonyManager.getNetworkType());
             }
             ApnSetting apn = apnContext.getApnSetting();
-            mPhone.notifyPreciseDataConnectionFailed(apnContext.getApnType(),
+            mPhone.notifyDataConnectionFailed(apnContext.getApnType(),
                     apn != null ? apn.getApnName() : null, cause);
 
             // Compose broadcast intent send to the specific carrier signaling receivers
-            Intent intent = new Intent(TelephonyIntents
+            Intent intent = new Intent(TelephonyManager
                     .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED);
-            intent.putExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY, cause);
-            intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnContext.getApnType());
+            intent.putExtra(TelephonyManager.EXTRA_ERROR_CODE, cause);
+            intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, apnContext.getApnType());
+            intent.putExtra(TelephonyManager.EXTRA_APN_TYPE_INT,
+                    ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType()));
             mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
 
             if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), cause, mPhone.getSubId())
@@ -2903,7 +2929,7 @@
             // Wait a bit before trying the next APN, so that
             // we're not tying up the RIL command channel
 
-            startAlarmForReconnect(delay, apnContext);
+            startReconnect(delay, apnContext);
         } else {
             // If we are not going to retry any APN, set this APN context to failed state.
             // This would be the final state of a data connection.
@@ -2920,17 +2946,19 @@
      *
      * @param status One of {@code NetworkAgent.VALID_NETWORK} or
      * {@code NetworkAgent.INVALID_NETWORK}.
+     * @param cid context id {@code cid}
      * @param redirectUrl If the Internet probe was redirected, this
      * is the destination it was redirected to, otherwise {@code null}
      */
-    private void onNetworkStatusChanged(int status, String redirectUrl) {
+    private void onNetworkStatusChanged(int status, int cid, String redirectUrl) {
         if (!TextUtils.isEmpty(redirectUrl)) {
-            Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
-            intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, redirectUrl);
+            Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED);
+            intent.putExtra(TelephonyManager.EXTRA_REDIRECTION_URL, redirectUrl);
             mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
             log("Notify carrier signal receivers with redirectUrl: " + redirectUrl);
         } else {
             final boolean isValid = status == NetworkAgent.VALID_NETWORK;
+            final DataConnection dc = getDataConnectionByContextId(cid);
             if (!mDsRecoveryHandler.isRecoveryOnBadNetworkEnabled()) {
                 if (DBG) log("Skip data stall recovery on network status change with in threshold");
                 return;
@@ -2939,7 +2967,9 @@
                 if (DBG) log("Skip data stall recovery on non WWAN");
                 return;
             }
-            mDsRecoveryHandler.processNetworkStatusChanged(isValid);
+            if (dc != null && dc.isValidationRequired()) {
+                mDsRecoveryHandler.processNetworkStatusChanged(isValid);
+            }
         }
     }
 
@@ -2983,11 +3013,6 @@
         }
         // If APN is still enabled, try to bring it back up automatically
         if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) {
-            try {
-                SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
-            } catch (RuntimeException ex) {
-                log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false");
-            }
             // Wait a bit before trying the next APN, so that
             // we're not tying up the RIL command channel.
             // This also helps in any external dependency to turn off the context.
@@ -2996,7 +3021,7 @@
             if (delay > 0) {
                 // Data connection is in IDLE state, so when we reconnect later, we'll rebuild
                 // the waiting APN list, which will also reset/reconfigure the retry manager.
-                startAlarmForReconnect(delay, apnContext);
+                startReconnect(delay, apnContext);
             }
         } else {
             boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean(
@@ -3035,7 +3060,7 @@
             if (DBG) log("onVoiceCallStarted stop polling");
             stopNetStatPoll();
             stopDataStallAlarm();
-            mPhone.notifyDataConnection();
+            mPhone.notifyAllActiveDataConnections();
         }
     }
 
@@ -3046,7 +3071,7 @@
             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                 startNetStatPoll();
                 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
-                mPhone.notifyDataConnection();
+                mPhone.notifyAllActiveDataConnections();
             } else {
                 // clean slate after call end.
                 resetPollStats();
@@ -3139,8 +3164,8 @@
             mApnSettingsInitializationLog.log("no APN found for carrier, operator: "
                     + operator);
             mPreferredApn = null;
-            // TODO: What is the right behavior?
-            //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
+            // Notify that there are no APN Settings,
+            mPhone.notifyDataConnectionFailed(null, null, DataFailCause.MISSING_UNKNOWN_APN);
         } else {
             mPreferredApn = getPreferredApn();
             if (mPreferredApn != null && !mPreferredApn.getOperatorNumeric().equals(operator)) {
@@ -3291,16 +3316,11 @@
                     apnList = sortApnListByPreferred(apnList);
                     if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
                     return apnList;
-                } else {
-                    if (DBG) log("buildWaitingApns: no preferred APN");
-                    setPreferredApn(-1);
-                    mPreferredApn = null;
                 }
-            } else {
-                if (DBG) log("buildWaitingApns: no preferred APN");
-                setPreferredApn(-1);
-                mPreferredApn = null;
             }
+            if (DBG) log("buildWaitingApns: no preferred APN");
+            setPreferredApn(-1);
+            mPreferredApn = null;
         }
 
         if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);
@@ -3510,7 +3530,7 @@
                         trySetupData(apnContext, REQUEST_TYPE_NORMAL);
                     } else {
                         loge("**** Default ApnContext not found ****");
-                        if (Build.IS_DEBUGGABLE) {
+                        if (TelephonyUtils.IS_DEBUGGABLE) {
                             throw new RuntimeException("Default ApnContext not found");
                         }
                     }
@@ -3588,8 +3608,9 @@
 
             case DctConstants.EVENT_NETWORK_STATUS_CHANGED:
                 int status = msg.arg1;
+                int cid = msg.arg2;
                 String url = (String) msg.obj;
-                onNetworkStatusChanged(status, url);
+                onNetworkStatusChanged(status, cid, url);
                 break;
 
             case DctConstants.EVENT_RADIO_AVAILABLE:
@@ -3780,7 +3801,8 @@
                 break;
             }
             case DctConstants.EVENT_DATA_RECONNECT:
-                onDataReconnect(msg.getData());
+                if (DBG) log("EVENT_DATA_RECONNECT: subId=" + msg.arg1);
+                onDataReconnect((ApnContext) msg.obj, msg.arg1);
                 break;
             case DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED:
                 onDataServiceBindingChanged((Boolean) ((AsyncResult) msg.obj).result);
@@ -3797,6 +3819,17 @@
             case DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED:
                 onDataEnabledOverrideRulesChanged();
                 break;
+            case DctConstants.EVENT_SERVICE_STATE_CHANGED:
+                reevaluateUnmeteredConnections();
+                break;
+            case DctConstants.EVENT_5G_TIMER_HYSTERESIS:
+                reevaluateUnmeteredConnections();
+                mHysteresis = false;
+                break;
+            case DctConstants.EVENT_5G_TIMER_WATCHDOG:
+                mWatchdog = false;
+                reevaluateUnmeteredConnections();
+                break;
             default:
                 Rlog.e("DcTracker", "Unhandled event=" + msg);
                 break;
@@ -3822,7 +3855,7 @@
 
     private int getCellLocationId() {
         int cid = -1;
-        CellLocation loc = mPhone.getCellLocation();
+        CellLocation loc = mPhone.getCellIdentity().asCellLocation();
 
         if (loc != null) {
             if (loc instanceof GsmCellLocation) {
@@ -3891,7 +3924,7 @@
         if (phoneSwitcher == null || serviceState == null) return false;
 
         // If voice is also not in service, don't auto attach.
-        if (serviceState.getVoiceRegState() != ServiceState.STATE_IN_SERVICE) return false;
+        if (serviceState.getState() != ServiceState.STATE_IN_SERVICE) return false;
 
         // If voice is on LTE or NR, don't auto attach as for LTE / NR data would be attached.
         if (serviceState.getVoiceNetworkType() == NETWORK_TYPE_LTE
@@ -3955,6 +3988,86 @@
         }
     }
 
+    private void reevaluateUnmeteredConnections() {
+        if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) {
+            if (mPhone.getServiceState().getNrState()
+                    == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
+                if (!m5GWasConnected) { // 4G -> 5G
+                    stopHysteresisAlarm();
+                    setDataConnectionUnmetered(true);
+                }
+                if (!mWatchdog) {
+                    startWatchdogAlarm();
+                }
+                m5GWasConnected = true;
+            } else {
+                if (m5GWasConnected) { // 5G -> 4G
+                    if (!mHysteresis && !startHysteresisAlarm()) {
+                        // hysteresis is not active but carrier does not support hysteresis
+                        stopWatchdogAlarm();
+                        setDataConnectionUnmetered(isNetworkTypeUnmetered(
+                                mTelephonyManager.getNetworkType(mPhone.getSubId())));
+                    }
+                    m5GWasConnected = false;
+                } else { // 4G -> 4G
+                    if (!hasMessages(DctConstants.EVENT_5G_TIMER_HYSTERESIS)) {
+                        stopWatchdogAlarm();
+                        setDataConnectionUnmetered(isNetworkTypeUnmetered(
+                                mTelephonyManager.getNetworkType(mPhone.getSubId())));
+                    }
+                    // do nothing if waiting for hysteresis alarm to go off
+                }
+            }
+        } else {
+            stopWatchdogAlarm();
+            stopHysteresisAlarm();
+            setDataConnectionUnmetered(isNetworkTypeUnmetered(
+                    mTelephonyManager.getNetworkType(mPhone.getSubId())));
+            m5GWasConnected = false;
+        }
+    }
+
+    private void setDataConnectionUnmetered(boolean isUnmetered) {
+        for (DataConnection dataConnection : mDataConnections.values()) {
+            dataConnection.onMeterednessChanged(isUnmetered);
+        }
+    }
+
+    private boolean isNetworkTypeUnmetered(@NetworkType int networkType) {
+        if (mSubscriptionPlans == null || mSubscriptionPlans.size() == 0) {
+            // safe return false if unable to get subscription plans or plans don't exist
+            return false;
+        }
+
+        long bitmask = TelephonyManager.getBitMaskForNetworkType(networkType);
+        boolean isGeneralUnmetered = true;
+        for (SubscriptionPlan plan : mSubscriptionPlans) {
+            // check plan applies to given network type
+            if ((plan.getNetworkTypesBitMask() & bitmask) == bitmask) {
+                // check plan is general or specific
+                if (plan.getNetworkTypes() == null) {
+                    if (!isPlanUnmetered(plan)) {
+                        // metered takes precedence over unmetered for safety
+                        isGeneralUnmetered = false;
+                    }
+                } else {
+                    // ensure network type unknown returns general value
+                    if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+                        // there is only 1 specific plan per network type, so return value if found
+                        return isPlanUnmetered(plan);
+                    }
+                }
+            }
+        }
+        return isGeneralUnmetered;
+    }
+
+    private boolean isPlanUnmetered(SubscriptionPlan plan) {
+        return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED
+                && (plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN
+                || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED);
+    }
+
     private void log(String s) {
         Rlog.d(mLogTag, s);
     }
@@ -4190,22 +4303,35 @@
                 return;
             }
             for (ApnContext apnContext : mApnContexts.values()) {
-                ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns();
-                ArrayList<ApnSetting> waitingApns = buildWaitingApns(
-                        apnContext.getApnType(), getDataRat());
-                if (VDBG) log("new waitingApns:" + waitingApns);
-                if ((currentWaitingApns != null)
-                        && ((waitingApns.size() != currentWaitingApns.size())
-                        // Check if the existing waiting APN list can cover the newly built APN
-                        // list. If yes, then we don't need to tear down the existing data call.
-                        // TODO: We probably need to rebuild APN list when roaming status changes.
-                        || !containsAllApns(currentWaitingApns, waitingApns))) {
-                    if (VDBG) log("new waiting apn is different for " + apnContext);
-                    apnContext.setWaitingApns(waitingApns);
-                    if (!apnContext.isDisconnected()) {
-                        if (VDBG) log("cleanUpConnectionsOnUpdatedApns for " + apnContext);
-                        apnContext.setReason(reason);
-                        cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext);
+                boolean cleanupRequired = false;
+                if (!apnContext.isDisconnected()) {
+                    ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns();
+                    ArrayList<ApnSetting> waitingApns = buildWaitingApns(
+                            apnContext.getApnType(), getDataRat());
+                    if (VDBG) log("new waitingApns:" + waitingApns);
+                    if ((currentWaitingApns != null)
+                            && ((waitingApns.size() != currentWaitingApns.size())
+                            // Check if the existing waiting APN list can cover the newly built APN
+                            // list. If yes, then we don't need to tear down the existing data call.
+                            // TODO: We probably need to rebuild APN list when roaming status
+                            //  changes.
+                            || !containsAllApns(currentWaitingApns, waitingApns))) {
+                        if (VDBG) log("new waiting apn is different for " + apnContext);
+                        apnContext.setWaitingApns(waitingApns);
+                        ApnSetting apnSetting = apnContext.getApnSetting();
+                        if (apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)) {
+                            if ((getPreferredApn() == null)
+                                    || !apnSetting.equals(getPreferredApn())) {
+                                cleanupRequired = true;
+                            }
+                        } else if (!waitingApns.contains(apnSetting)) {
+                            cleanupRequired = true;
+                        }
+                        if (cleanupRequired) {
+                            if (VDBG) log("cleanUpConnectionsOnUpdatedApns for " + apnContext);
+                            apnContext.setReason(reason);
+                            cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext);
+                        }
                     }
                 }
             }
@@ -4393,11 +4519,15 @@
             for (ApnContext apnContext : apnContextList) {
                 String apnType = apnContext.getApnType();
 
-                final Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE);
-                intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnType);
-                intent.putExtra(TelephonyIntents.EXTRA_APN_PROTO_KEY, pcoData.bearerProto);
-                intent.putExtra(TelephonyIntents.EXTRA_PCO_ID_KEY, pcoData.pcoId);
-                intent.putExtra(TelephonyIntents.EXTRA_PCO_VALUE_KEY, pcoData.contents);
+                final Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE);
+                intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, apnType);
+                intent.putExtra(TelephonyManager.EXTRA_APN_TYPE_INT,
+                        ApnSetting.getApnTypesBitmaskFromString(apnType));
+                intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, pcoData.bearerProto);
+                intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL_INT,
+                        ApnSetting.getProtocolIntFromString(pcoData.bearerProto));
+                intent.putExtra(TelephonyManager.EXTRA_PCO_ID, pcoData.pcoId);
+                intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, pcoData.contents);
                 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
             }
         }
@@ -4503,6 +4633,9 @@
             if (getOverallState() == DctConstants.State.CONNECTED) {
                 // Go through a series of recovery steps, each action transitions to the next action
                 @RecoveryAction final int recoveryAction = getRecoveryAction();
+                final int signalStrength = mPhone.getSignalStrength().getLevel();
+                TelephonyMetrics.getInstance().writeSignalStrengthEvent(
+                        mPhone.getPhoneId(), signalStrength);
                 TelephonyMetrics.getInstance().writeDataStallEvent(
                         mPhone.getPhoneId(), recoveryAction);
                 broadcastDataStallDetected(recoveryAction);
@@ -4577,7 +4710,7 @@
         long sent, received;
 
         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
-        mDataStallTxRxSum.updateTcpTxRxSum();
+        mDataStallTxRxSum.updateTotalTxRxSum();
 
         if (VDBG_STALL) {
             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
@@ -4736,7 +4869,7 @@
         int delayInMs = Settings.Global.getInt(mResolver,
                                 Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
                                 PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT);
-        if (Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             // Allow debug code to use a system property to provide another value
             String delayInMsStrg = Integer.toString(delayInMs);
             delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg);
@@ -4771,6 +4904,36 @@
         }
     }
 
+    /**
+     * 5G connection reevaluation alarms
+     */
+    private boolean startHysteresisAlarm() {
+        if (mHysteresisTimeMs > 0) {
+            // only create hysteresis alarm if CarrierConfig allows it
+            sendMessageDelayed(obtainMessage(DctConstants.EVENT_5G_TIMER_HYSTERESIS),
+                    mHysteresisTimeMs);
+            mHysteresis = true;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private void stopHysteresisAlarm() {
+        removeMessages(DctConstants.EVENT_5G_TIMER_HYSTERESIS);
+        mHysteresis = false;
+    }
+
+    private void startWatchdogAlarm() {
+        sendMessageDelayed(obtainMessage(DctConstants.EVENT_5G_TIMER_WATCHDOG), mWatchdogTimeMs);
+        mWatchdog = true;
+    }
+
+    private void stopWatchdogAlarm() {
+        removeMessages(DctConstants.EVENT_5G_TIMER_WATCHDOG);
+        mWatchdog = false;
+    }
+
     private static DataProfile createDataProfile(ApnSetting apn, boolean isPreferred) {
         return createDataProfile(apn, apn.getProfileId(), isPreferred);
     }
diff --git a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
index fa9723a..0f80fce 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
@@ -21,7 +21,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
 import android.net.NetworkRequest;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
@@ -29,18 +29,19 @@
 import android.os.Message;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation.ApnType;
-import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
 import android.telephony.data.ApnSetting;
 import android.util.LocalLog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneSwitcher;
 import com.android.internal.telephony.SubscriptionController;
-import com.android.internal.telephony.SubscriptionMonitor;
 import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType;
 import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType;
 import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -59,8 +60,10 @@
 
     private static final int TELEPHONY_NETWORK_SCORE = 50;
 
-    private static final int EVENT_ACTIVE_PHONE_SWITCH              = 1;
-    private static final int EVENT_SUBSCRIPTION_CHANGED             = 2;
+    @VisibleForTesting
+    public static final int EVENT_ACTIVE_PHONE_SWITCH               = 1;
+    @VisibleForTesting
+    public static final int EVENT_SUBSCRIPTION_CHANGED              = 2;
     private static final int EVENT_NETWORK_REQUEST                  = 3;
     private static final int EVENT_NETWORK_RELEASE                  = 4;
     private static final int EVENT_DATA_HANDOVER_NEEDED             = 5;
@@ -68,7 +71,6 @@
 
     private final PhoneSwitcher mPhoneSwitcher;
     private final SubscriptionController mSubscriptionController;
-    private final SubscriptionMonitor mSubscriptionMonitor;
     private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE);
 
     // Key: network request. Value: the transport of DcTracker it applies to,
@@ -83,11 +85,11 @@
 
     private int mSubscriptionId;
 
-    private final Handler mInternalHandler;
+    @VisibleForTesting
+    public final Handler mInternalHandler;
 
 
-    public TelephonyNetworkFactory(SubscriptionMonitor subscriptionMonitor, Looper looper,
-                                   Phone phone) {
+    public TelephonyNetworkFactory(Looper looper, Phone phone) {
         super(looper, phone.getContext(), "TelephonyNetworkFactory[" + phone.getPhoneId()
                 + "]", null);
         mPhone = phone;
@@ -100,7 +102,6 @@
         setScoreFilter(TELEPHONY_NETWORK_SCORE);
 
         mPhoneSwitcher = PhoneSwitcher.getInstance();
-        mSubscriptionMonitor = subscriptionMonitor;
         LOG_TAG = "TelephonyNetworkFactory[" + mPhone.getPhoneId() + "]";
 
         mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH,
@@ -109,12 +110,20 @@
                 EVENT_DATA_HANDOVER_NEEDED);
 
         mSubscriptionId = INVALID_SUBSCRIPTION_ID;
-        mSubscriptionMonitor.registerForSubscriptionChanged(mPhone.getPhoneId(), mInternalHandler,
-                EVENT_SUBSCRIPTION_CHANGED, null);
+        SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener(
+                mSubscriptionsChangedListener);
 
         register();
     }
 
+    private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener =
+            new SubscriptionManager.OnSubscriptionsChangedListener() {
+                @Override
+                public void onSubscriptionsChanged() {
+                    mInternalHandler.sendEmptyMessage(EVENT_SUBSCRIPTION_CHANGED);
+                }
+            };
+
     private NetworkCapabilities makeNetworkFilter(SubscriptionController subscriptionController,
             int phoneId) {
         final int subscriptionId = subscriptionController.getSubIdUsingPhoneId(phoneId);
@@ -136,7 +145,8 @@
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        nc.setNetworkSpecifier(new StringNetworkSpecifier(String.valueOf(subscriptionId)));
+        nc.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                .setSubscriptionId(subscriptionId).build());
         return nc;
     }
 
@@ -338,16 +348,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..5635089 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
@@ -28,7 +28,6 @@
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.Annotation.ApnType;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.data.ApnSetting;
 import android.util.LocalLog;
 import android.util.SparseArray;
@@ -38,8 +37,9 @@
 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 com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -297,7 +297,7 @@
     }
 
     private static boolean areNetworksValid(QualifiedNetworks networks) {
-        if (networks.qualifiedNetworks == null) {
+        if (networks.qualifiedNetworks == null || networks.qualifiedNetworks.length == 0) {
             return false;
         }
         for (int network : networks.qualifiedNetworks) {
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
index af2c61b..7fdd408 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
@@ -28,7 +28,6 @@
 import android.os.SystemProperties;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting;
@@ -36,7 +35,6 @@
 import android.text.TextUtils;
 import android.util.LocalLog;
 
-import com.android.i18n.phonenumbers.ShortNumberInfo;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.LocaleTracker;
@@ -49,6 +47,9 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.phone.ecc.nano.ProtobufEccData;
 import com.android.phone.ecc.nano.ProtobufEccData.EccInfo;
+import com.android.telephony.Rlog;
+
+import com.google.i18n.phonenumbers.ShortNumberInfo;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
@@ -75,7 +76,8 @@
     private static final String EMERGENCY_NUMBER_DB_OTA_FILE_NAME = "emergency_number_db";
     private static final String EMERGENCY_NUMBER_DB_OTA_FILE_PATH =
             "misc/emergencynumberdb/" + EMERGENCY_NUMBER_DB_OTA_FILE_NAME;
-
+    private File mEmergencyNumberDbOtaFilePath = new File(Environment.getDataDirectory(),
+            EMERGENCY_NUMBER_DB_OTA_FILE_PATH);
 
     /** @hide */
     public static boolean DBG = false;
@@ -124,6 +126,8 @@
     private static final int EVENT_UPDATE_EMERGENCY_NUMBER_PREFIX = 4;
     /** Event indicating the update for the OTA emergency number database. */
     private static final int EVENT_UPDATE_OTA_EMERGENCY_NUMBER_DB = 5;
+    /** Event indicating the override for the test OTA emergency number database. */
+    private static final int EVENT_OVERRIDE_TEST_OTA_EMERGENCY_NUMBER_DB_FILE_PATH = 6;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -153,11 +157,6 @@
                     updateEmergencyCountryIsoAllPhones(countryIso);
                 }
                 return;
-            } else if (intent.getAction().equals(
-                    TelephonyManager.ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED)) {
-                logd("ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED: triggered");
-                updateOtaEmergencyNumberDatabase();
-                return;
             }
         }
     };
@@ -183,8 +182,6 @@
                     CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
             // Receive Telephony Network Country Changes
             filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
-            // Receive Emergency Number OTA Update Changes
-            filter.addAction(TelephonyManager.ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED);
 
             mPhone.getContext().registerReceiver(mIntentReceiver, filter);
         } else {
@@ -225,7 +222,7 @@
                 }
                 break;
             case EVENT_UPDATE_EMERGENCY_NUMBER_TEST_MODE:
-                if (msg.obj == null) {
+                if (msg.obj == null && msg.arg1 != RESET_EMERGENCY_NUMBER_TEST_MODE) {
                     loge("EVENT_UPDATE_EMERGENCY_NUMBER_TEST_MODE: Result from"
                             + " executeEmergencyNumberTestModeCommand is null.");
                 } else {
@@ -244,6 +241,14 @@
             case EVENT_UPDATE_OTA_EMERGENCY_NUMBER_DB:
                 updateOtaEmergencyNumberListDatabaseAndNotify();
                 break;
+            case EVENT_OVERRIDE_TEST_OTA_EMERGENCY_NUMBER_DB_FILE_PATH:
+                if (msg.obj == null) {
+                    loge("EVENT_OVERRIDE_TEST_OTA_EMERGENCY_NUMBER_DB_FILE_PATH:"
+                            + " Result from otaFilePath is null.");
+                } else {
+                    overrideTestOtaEmergencyNumberDbFilePath((String) msg.obj);
+                }
+                break;
         }
     }
 
@@ -341,6 +346,16 @@
         this.obtainMessage(EVENT_UPDATE_OTA_EMERGENCY_NUMBER_DB).sendToTarget();
     }
 
+    /**
+     * Override the test OTA Emergency Number database file path.
+     *
+     * @hide
+     */
+    public void updateTestOtaEmergencyNumberDbFilePath(String otaFilePath) {
+        this.obtainMessage(
+                EVENT_OVERRIDE_TEST_OTA_EMERGENCY_NUMBER_DB_FILE_PATH, otaFilePath).sendToTarget();
+    }
+
     private EmergencyNumber convertEmergencyNumberFromEccInfo(EccInfo eccInfo, String countryIso) {
         String phoneNumber = eccInfo.phoneNumber.trim();
         if (phoneNumber.isEmpty()) {
@@ -441,8 +456,7 @@
         List<EmergencyNumber> updatedOtaEmergencyNumberList = new ArrayList<>();
         try {
             inputStream = new BufferedInputStream(
-                    new FileInputStream(new File(Environment.getDataDirectory(),
-                            EMERGENCY_NUMBER_DB_OTA_FILE_PATH)));
+                    new FileInputStream(mEmergencyNumberDbOtaFilePath));
             allEccMessages = ProtobufEccData.AllInfo.parseFrom(readInputStreamToByteArray(
                     new GZIPInputStream(inputStream)));
             logd(mCountryIso + " ota emergency database is loaded. Ver: " + otaDatabaseVersion);
@@ -539,6 +553,26 @@
         notifyEmergencyNumberList();
     }
 
+    private void overrideTestOtaEmergencyNumberDbFilePath(String otaFilePath) {
+        logd("overrideTestOtaEmergencyNumberDbFilePath:" + otaFilePath);
+        if (otaFilePath.equals("RESET")) {
+            mEmergencyNumberDbOtaFilePath = new File(Environment.getDataDirectory(),
+                    EMERGENCY_NUMBER_DB_OTA_FILE_PATH);
+            return;
+        }
+        String[] otaFilePathParts = otaFilePath.split("@");
+        if (otaFilePathParts.length != 2) {
+            loge("overrideTestOtaEmergencyNumberDbFilePath: otaFilePath length error");
+            return;
+        }
+        if (otaFilePathParts[0].equals("sdcard")) {
+            mEmergencyNumberDbOtaFilePath = new File(
+                    Environment.getExternalStorageDirectory(), otaFilePathParts[1]);
+        } else {
+            loge("overrideTestOtaEmergencyNumberDbFilePath: otaFilePath prefix error");
+        }
+    }
+
     private void updateOtaEmergencyNumberListDatabaseAndNotify() {
         logd("updateOtaEmergencyNumberListDatabaseAndNotify():"
                 + " receiving Emegency Number database OTA update");
@@ -724,6 +758,10 @@
         return mCountryIso;
     }
 
+    public int getEmergencyNumberDbVersion() {
+        return mCurrentDatabaseVersion;
+    }
+
     private synchronized void updateEmergencyCountryIso(String countryIso) {
         mCountryIso = countryIso;
     }
@@ -1013,7 +1051,7 @@
         }
         for (EmergencyNumber num : updatedEmergencyNumberList) {
             TelephonyMetrics.getInstance().writeEmergencyNumberUpdateEvent(
-                    mPhone.getPhoneId(), num);
+                    mPhone.getPhoneId(), num, getEmergencyNumberDbVersion());
         }
     }
 
@@ -1029,6 +1067,12 @@
         ipw.println(" Hal Version:" + mPhone.getHalVersion());
         ipw.println(" ========================================= ");
 
+        ipw.println(" Country Iso:" + getEmergencyCountryIso());
+        ipw.println(" ========================================= ");
+
+        ipw.println(" Database Version:" + getEmergencyNumberDbVersion());
+        ipw.println(" ========================================= ");
+
         ipw.println("mEmergencyNumberListDatabaseLocalLog:");
         ipw.increaseIndent();
         mEmergencyNumberListDatabaseLocalLog.dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java
index 874bd51..5b2c3c6 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java
@@ -46,6 +46,7 @@
 import android.service.euicc.IDownloadSubscriptionCallback;
 import android.service.euicc.IEraseSubscriptionsCallback;
 import android.service.euicc.IEuiccService;
+import android.service.euicc.IEuiccServiceDumpResultCallback;
 import android.service.euicc.IGetDefaultDownloadableSubscriptionListCallback;
 import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback;
 import android.service.euicc.IGetEidCallback;
@@ -56,6 +57,7 @@
 import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback;
 import android.service.euicc.ISwitchToSubscriptionCallback;
 import android.service.euicc.IUpdateSubscriptionNicknameCallback;
+import android.telephony.PackageChangeReceiver;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccCardInfo;
@@ -68,7 +70,6 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.IState;
 import com.android.internal.util.State;
@@ -95,7 +96,7 @@
      * true or onServiceDisconnected is called (and no package change has occurred which should
      * force us to reestablish the binding).
      */
-    private static final int BIND_TIMEOUT_MILLIS = 30000;
+    static final int BIND_TIMEOUT_MILLIS = 30000;
 
     /**
      * Maximum amount of idle time to hold the binding while in {@link ConnectedState}. After this,
@@ -147,6 +148,7 @@
     private static final int CMD_GET_OTA_STATUS = 111;
     private static final int CMD_START_OTA_IF_NECESSARY = 112;
     private static final int CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS = 113;
+    private static final int CMD_DUMP_EUICC_SERVICE = 114;
 
     private static boolean isEuiccCommand(int what) {
         return what >= CMD_GET_EID;
@@ -154,7 +156,7 @@
 
     /** Flags to use when querying PackageManager for Euicc component implementations. */
     private static final int EUICC_QUERY_FLAGS =
-            PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+            PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AUTO
                     | PackageManager.GET_RESOLVED_FILTER;
 
     /**
@@ -322,12 +324,19 @@
         void onRetainSubscriptionsComplete(int result);
     }
 
+    /** Callback class for {@link #dumpEuiccService(DumpEuiccCommandCallback)}   }*/
+    @VisibleForTesting(visibility = PACKAGE)
+    public interface DumpEuiccServiceCommandCallback extends BaseEuiccCommandCallback {
+        /** Called when the retain command has completed (though it may have failed). */
+        void onDumpEuiccServiceComplete(String logs);
+    }
+
     private Context mContext;
     private PackageManager mPm;
     private TelephonyManager mTm;
     private SubscriptionManager mSm;
 
-    private final PackageMonitor mPackageMonitor = new EuiccPackageMonitor();
+    private final PackageChangeReceiver mPackageMonitor = new EuiccPackageMonitor();
     private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -393,7 +402,7 @@
         mSelectedComponent = findBestComponent();
         setInitialState(mSelectedComponent != null ? mAvailableState : mUnavailableState);
 
-        mPackageMonitor.register(mContext, null /* thread */, false /* externalStorage */);
+        mPackageMonitor.register(mContext, null /* thread */, null /* user */);
         mContext.registerReceiver(
                 mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
 
@@ -521,6 +530,14 @@
         sendMessage(CMD_RETAIN_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback);
     }
 
+    /** Asynchronously calls the currently bound EuiccService implementation to dump its states */
+    @VisibleForTesting(visibility = PACKAGE)
+    public void dumpEuiccService(DumpEuiccServiceCommandCallback callback) {
+        sendMessage(CMD_DUMP_EUICC_SERVICE, TelephonyManager.UNSUPPORTED_CARD_ID /* ignored */,
+                0 /* arg2 */,
+                callback);
+    }
+
     /**
      * State in which no EuiccService is available.
      *
@@ -923,6 +940,20 @@
                                     });
                             break;
                         }
+                        case CMD_DUMP_EUICC_SERVICE: {
+                            mEuiccService.dump(new IEuiccServiceDumpResultCallback.Stub() {
+                                @Override
+                                public void onComplete(String logs)
+                                        throws RemoteException {
+                                    sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
+                                        ((DumpEuiccServiceCommandCallback) callback)
+                                                .onDumpEuiccServiceComplete(logs);
+                                        onCommandEnd(callback);
+                                    });
+                                }
+                            });
+                            break;
+                        }
                         default: {
                             Log.wtf(TAG, "Unimplemented eUICC command: " + message.what);
                             callback.onEuiccServiceUnavailable();
@@ -968,6 +999,7 @@
             case CMD_RETAIN_SUBSCRIPTIONS:
             case CMD_GET_OTA_STATUS:
             case CMD_START_OTA_IF_NECESSARY:
+            case CMD_DUMP_EUICC_SERVICE:
                 return (BaseEuiccCommandCallback) message.obj;
             case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA:
                 return ((GetMetadataRequest) message.obj).mCallback;
@@ -1124,19 +1156,19 @@
         sendMessage(CMD_SERVICE_DISCONNECTED);
     }
 
-    private class EuiccPackageMonitor extends PackageMonitor {
+    private class EuiccPackageMonitor extends PackageChangeReceiver {
         @Override
-        public void onPackageAdded(String packageName, int reason) {
+        public void onPackageAdded(String packageName) {
             sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
         }
 
         @Override
-        public void onPackageRemoved(String packageName, int reason) {
+        public void onPackageRemoved(String packageName) {
             sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
         }
 
         @Override
-        public void onPackageUpdateFinished(String packageName, int uid) {
+        public void onPackageUpdateFinished(String packageName) {
             sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
         }
 
@@ -1146,13 +1178,12 @@
         }
 
         @Override
-        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+        public void onHandleForceStop(String[] packages, boolean doit) {
             if (doit) {
                 for (String packageName : packages) {
                     sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
                 }
             }
-            return super.onHandleForceStop(intent, packages, uid, doit);
         }
 
         private void sendPackageChange(String packageName, boolean forceUnbindForThisPackage) {
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java
index 7c69cfb..fbca21b 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java
@@ -15,8 +15,11 @@
  */
 package com.android.internal.telephony.euicc;
 
+import static com.android.internal.telephony.euicc.EuiccConnector.BIND_TIMEOUT_MILLIS;
+
 import android.Manifest;
 import android.Manifest.permission;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -53,8 +56,10 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 /** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */
@@ -83,6 +88,11 @@
     private final AppOpsManager mAppOpsManager;
     private final PackageManager mPackageManager;
 
+    // These values should be set or updated upon 1) system boot, 2) EuiccService/LPA is bound to
+    // the phone process, 3) values are updated remotely by server flags.
+    private List<String> mSupportedCountries;
+    private List<String> mUnsupportedCountries;
+
     /** Initialize the instance. Should only be called once. */
     public static EuiccController init(Context context) {
         synchronized (EuiccController.class) {
@@ -241,6 +251,89 @@
                 subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent);
     }
 
+    /**
+     * Sets the supported or unsupported countries for eUICC.
+     *
+     * <p>If {@code isSupported} is true, the supported country list will be replaced by
+     * {@code countriesList}. Otherwise, unsupported country list will be replaced by
+     * {@code countriesList}. For how we determine whether a country is supported by checking
+     * supported and unsupported country list please check {@link EuiccManager#isSupportedCountry}.
+     *
+     * @param isSupported should be true if caller wants to set supported country list. If
+     * isSupported is false, un-supported country list will be updated.
+     * @param countriesList is a list of strings contains country ISO codes in uppercase.
+     */
+    @Override
+    public void setSupportedCountries(boolean isSupported, @NonNull List<String> countriesList) {
+        if (isSupported) {
+            mSupportedCountries = countriesList;
+        } else {
+            mUnsupportedCountries = countriesList;
+        }
+    }
+
+    /**
+     * Gets the supported or unsupported countries for eUICC.
+     *
+     * <p>If {@code isSupported} is true, the supported country list will be returned. Otherwise,
+     * unsupported country list will be returned.
+     *
+     * @param isSupported should be true if caller wants to get supported country list. If
+     * isSupported is false, unsupported country list will be returned.
+     * @return a list of strings contains country ISO codes in uppercase.
+     */
+    @Override
+    @NonNull
+    public List<String> getSupportedCountries(boolean isSupported) {
+        if (isSupported && mSupportedCountries != null) {
+            return mSupportedCountries;
+        } else if (!isSupported && mUnsupportedCountries != null) {
+            return mUnsupportedCountries;
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns whether the given country supports eUICC.
+     *
+     * <p>Supported country list has a higher prority than unsupported country list. If the
+     * supported country list is not empty, {@code countryIso} will be considered as supported when
+     * it exists in the supported country list. Otherwise {@code countryIso} is not supported. If
+     * the supported country list is empty, {@code countryIso} will be considered as supported if it
+     * does not exist in the unsupported country list. Otherwise {@code countryIso} is not
+     * supported. If both supported and unsupported country lists are empty, then all countries are
+     * consider be supported. For how to set supported and unsupported country list, please check
+     * {@link #setSupportedCountries}.
+     *
+     * @param countryIso should be the ISO-3166 country code is provided in uppercase 2 character
+     * format.
+     * @return whether the given country supports eUICC or not.
+     */
+    @Override
+    public boolean isSupportedCountry(@NonNull String countryIso) {
+        if (mSupportedCountries == null || mSupportedCountries.isEmpty()) {
+            Log.i(TAG, "Using blacklist unsupportedCountries=" + mUnsupportedCountries);
+            return !isEsimUnsupportedCountry(countryIso);
+        } else {
+            Log.i(TAG, "Using whitelist supportedCountries=" + mSupportedCountries);
+            return isEsimSupportedCountry(countryIso);
+        }
+    }
+
+    private boolean isEsimSupportedCountry(String countryIso) {
+        if (mSupportedCountries == null || TextUtils.isEmpty(countryIso)) {
+            return true;
+        }
+        return mSupportedCountries.contains(countryIso);
+    }
+
+    private boolean isEsimUnsupportedCountry(String countryIso) {
+        if (mUnsupportedCountries == null || TextUtils.isEmpty(countryIso)) {
+            return false;
+        }
+        return mUnsupportedCountries.contains(countryIso);
+    }
+
     void getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription,
             boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
         if (!callerCanWriteEmbeddedSubscriptions()) {
@@ -1110,12 +1203,37 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
         final long token = Binder.clearCallingIdentity();
+        pw.println("===== BEGIN EUICC CLINIC =====");
         try {
+            pw.println("===== EUICC CONNECTOR =====");
             mConnector.dump(fd, pw, args);
+            final CountDownLatch countDownLatch = new CountDownLatch(1);
+            mConnector.dumpEuiccService(new EuiccConnector.DumpEuiccServiceCommandCallback() {
+                @Override
+                public void onDumpEuiccServiceComplete(String logs) {
+                    pw.println("===== EUICC SERVICE =====");
+                    pw.println(logs);
+                    countDownLatch.countDown();
+                }
+
+                @Override
+                public void onEuiccServiceUnavailable() {
+                    pw.println("===== EUICC SERVICE UNAVAILABLE =====");
+                    countDownLatch.countDown();
+                }
+            });
+
+            // Wait up to 30 seconds
+            if (!countDownLatch.await(BIND_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                pw.println("===== EUICC SERVICE TIMEOUT =====");
+            }
+        } catch (InterruptedException e) {
+            pw.println("===== EUICC SERVICE INTERRUPTED =====");
         } finally {
+            pw.println("===== END EUICC CLINIC =====");
             Binder.restoreCallingIdentity(token);
         }
     }
@@ -1228,7 +1346,8 @@
 
         final PackageInfo info;
         try {
-            info = mPackageManager.getPackageInfo(callingPackage, PackageManager.GET_SIGNATURES);
+            info = mPackageManager.getPackageInfo(callingPackage,
+                PackageManager.GET_SIGNING_CERTIFICATES);
         } catch (PackageManager.NameNotFoundException e) {
             Log.e(TAG, "Calling package valid but gone");
             return false;
diff --git a/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java b/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
deleted file mode 100644
index 052d89c..0000000
--- a/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2013 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.gsm;
-
-import static com.android.internal.telephony.gsm.SmsCbConstants.MESSAGE_ID_CMAS_GEO_FENCING_TRIGGER;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncResult;
-import android.os.Message;
-import android.provider.Telephony.CellBroadcasts;
-import android.telephony.CellLocation;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.telephony.TelephonyManager;
-import android.telephony.gsm.GsmCellLocation;
-import android.text.format.DateUtils;
-
-import com.android.internal.telephony.CbGeoUtils.Geometry;
-import com.android.internal.telephony.CellBroadcastHandler;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.gsm.GsmSmsCbMessage.GeoFencingTriggerMessage;
-import com.android.internal.telephony.gsm.GsmSmsCbMessage.GeoFencingTriggerMessage.CellBroadcastIdentity;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Handler for 3GPP format Cell Broadcasts. Parent class can also handle CDMA Cell Broadcasts.
- */
-public class GsmCellBroadcastHandler extends CellBroadcastHandler {
-    private static final boolean VDBG = false;  // log CB PDU data
-
-    /** Indicates that a message is not being broadcasted. */
-    private static final String MESSAGE_NOT_BROADCASTED = "0";
-
-    /** This map holds incomplete concatenated messages waiting for assembly. */
-    @UnsupportedAppUsage
-    private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap =
-            new HashMap<SmsCbConcatInfo, byte[][]>(4);
-
-    protected GsmCellBroadcastHandler(Context context, Phone phone) {
-        super("GsmCellBroadcastHandler", context, phone);
-        phone.mCi.setOnNewGsmBroadcastSms(getHandler(), EVENT_NEW_SMS_MESSAGE, null);
-    }
-
-    @Override
-    protected void onQuitting() {
-        mPhone.mCi.unSetOnNewGsmBroadcastSms(getHandler());
-        super.onQuitting();     // release wakelock
-    }
-
-    /**
-     * Create a new CellBroadcastHandler.
-     * @param context the context to use for dispatching Intents
-     * @return the new handler
-     */
-    public static GsmCellBroadcastHandler makeGsmCellBroadcastHandler(Context context,
-            Phone phone) {
-        GsmCellBroadcastHandler handler = new GsmCellBroadcastHandler(context, phone);
-        handler.start();
-        return handler;
-    }
-
-    /**
-     * Find the cell broadcast messages specify by the geo-fencing trigger message and perform a
-     * geo-fencing check for these messages.
-     * @param geoFencingTriggerMessage the trigger message
-     *
-     * @return {@code True} if geo-fencing is need for some cell broadcast message.
-     */
-    private boolean handleGeoFencingTriggerMessage(
-            GeoFencingTriggerMessage geoFencingTriggerMessage) {
-        final List<SmsCbMessage> cbMessages = new ArrayList<>();
-        final List<Uri> cbMessageUris = new ArrayList<>();
-
-        // Only consider the cell broadcast received within 24 hours.
-        long lastReceivedTime = System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS;
-
-        // Find the cell broadcast message identify by the message identifier and serial number
-        // and is not broadcasted.
-        String where = CellBroadcasts.SERVICE_CATEGORY + "=? AND "
-                + CellBroadcasts.SERIAL_NUMBER + "=? AND "
-                + CellBroadcasts.MESSAGE_BROADCASTED + "=? AND "
-                + CellBroadcasts.RECEIVED_TIME + ">?";
-
-        ContentResolver resolver = mContext.getContentResolver();
-        for (CellBroadcastIdentity identity : geoFencingTriggerMessage.cbIdentifiers) {
-            try (Cursor cursor = resolver.query(CELL_BROADCAST_URI,
-                    CellBroadcasts.QUERY_COLUMNS_FWK,
-                    where,
-                    new String[] { Integer.toString(identity.messageIdentifier),
-                            Integer.toString(identity.serialNumber), MESSAGE_NOT_BROADCASTED,
-                            Long.toString(lastReceivedTime) },
-                    null /* sortOrder */)) {
-                if (cursor != null) {
-                    while (cursor.moveToNext()) {
-                        cbMessages.add(SmsCbMessage.createFromCursor(cursor));
-                        cbMessageUris.add(ContentUris.withAppendedId(CELL_BROADCAST_URI,
-                                cursor.getInt(cursor.getColumnIndex(CellBroadcasts._ID))));
-                    }
-                }
-            }
-        }
-
-        List<Geometry> commonBroadcastArea = new ArrayList<>();
-        if (geoFencingTriggerMessage.shouldShareBroadcastArea()) {
-            for (SmsCbMessage msg : cbMessages) {
-                if (msg.getGeometries() != null) {
-                    commonBroadcastArea.addAll(msg.getGeometries());
-                }
-            }
-        }
-
-        // ATIS doesn't specify the geo fencing maximum wait time for the cell broadcasts specified
-        // in geo fencing trigger message. We will pick the largest maximum wait time among these
-        // cell broadcasts.
-        int maximumWaitTimeSec = 0;
-        for (SmsCbMessage msg : cbMessages) {
-            maximumWaitTimeSec = Math.max(maximumWaitTimeSec, msg.getMaximumWaitingTime());
-        }
-
-        if (DBG) {
-            logd("Geo-fencing trigger message = " + geoFencingTriggerMessage);
-            for (SmsCbMessage msg : cbMessages) {
-                logd(msg.toString());
-            }
-        }
-
-        if (cbMessages.isEmpty()) {
-            if (DBG) logd("No CellBroadcast message need to be broadcasted");
-            return false;
-        }
-
-        requestLocationUpdate(location -> {
-            if (location == null) {
-                // If the location is not available, broadcast the messages directly.
-                broadcastMessage(cbMessages, cbMessageUris);
-            } else {
-                for (int i = 0; i < cbMessages.size(); i++) {
-                    List<Geometry> broadcastArea = !commonBroadcastArea.isEmpty()
-                            ? commonBroadcastArea : cbMessages.get(i).getGeometries();
-                    if (broadcastArea == null || broadcastArea.isEmpty()) {
-                        broadcastMessage(cbMessages.get(i), cbMessageUris.get(i));
-                    } else {
-                        performGeoFencing(cbMessages.get(i), cbMessageUris.get(i), broadcastArea,
-                                location);
-                    }
-                }
-            }
-        }, maximumWaitTimeSec);
-        return true;
-    }
-
-    /**
-     * Handle 3GPP-format Cell Broadcast messages sent from radio.
-     *
-     * @param message the message to process
-     * @return true if need to wait for geo-fencing or an ordered broadcast was sent.
-     */
-    @Override
-    protected boolean handleSmsMessage(Message message) {
-        if (message.obj instanceof AsyncResult) {
-            SmsCbHeader header = createSmsCbHeader((AsyncResult) message.obj);
-            if (header == null) return false;
-
-            AsyncResult ar = (AsyncResult) message.obj;
-            byte[] pdu = (byte[]) ar.result;
-            if (header.getServiceCategory() == MESSAGE_ID_CMAS_GEO_FENCING_TRIGGER) {
-                GeoFencingTriggerMessage triggerMessage =
-                        GsmSmsCbMessage.createGeoFencingTriggerMessage(pdu);
-                if (triggerMessage != null) {
-                    return handleGeoFencingTriggerMessage(triggerMessage);
-                }
-            } else {
-                SmsCbMessage cbMessage = handleGsmBroadcastSms(header, ar);
-                if (cbMessage != null) {
-                    handleBroadcastSms(cbMessage);
-                    return true;
-                }
-                if (VDBG) log("Not handled GSM broadcasts.");
-            }
-        }
-        return super.handleSmsMessage(message);
-    }
-
-    /**
-     * Handle 3GPP format SMS-CB message.
-     * @param header the cellbroadcast header.
-     * @param ar the AsyncResult containing the received PDUs
-     */
-    private SmsCbMessage handleGsmBroadcastSms(SmsCbHeader header, AsyncResult ar) {
-        try {
-            byte[] receivedPdu = (byte[]) ar.result;
-
-            if (VDBG) {
-                int pduLength = receivedPdu.length;
-                for (int i = 0; i < pduLength; i += 8) {
-                    StringBuilder sb = new StringBuilder("SMS CB pdu data: ");
-                    for (int j = i; j < i + 8 && j < pduLength; j++) {
-                        int b = receivedPdu[j] & 0xff;
-                        if (b < 0x10) {
-                            sb.append('0');
-                        }
-                        sb.append(Integer.toHexString(b)).append(' ');
-                    }
-                    log(sb.toString());
-                }
-            }
-
-            if (VDBG) log("header=" + header);
-            String plmn = TelephonyManager.from(mContext).getNetworkOperatorForPhone(
-                    mPhone.getPhoneId());
-            int lac = -1;
-            int cid = -1;
-            CellLocation cl = mPhone.getCellLocation();
-            // Check if cell location is GsmCellLocation.  This is required to support
-            // dual-mode devices such as CDMA/LTE devices that require support for
-            // both 3GPP and 3GPP2 format messages
-            if (cl instanceof GsmCellLocation) {
-                GsmCellLocation cellLocation = (GsmCellLocation)cl;
-                lac = cellLocation.getLac();
-                cid = cellLocation.getCid();
-            }
-
-            SmsCbLocation location;
-            switch (header.getGeographicalScope()) {
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE:
-                    location = new SmsCbLocation(plmn, lac, -1);
-                    break;
-
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE:
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE:
-                    location = new SmsCbLocation(plmn, lac, cid);
-                    break;
-
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE:
-                default:
-                    location = new SmsCbLocation(plmn);
-                    break;
-            }
-
-            byte[][] pdus;
-            int pageCount = header.getNumberOfPages();
-            if (pageCount > 1) {
-                // Multi-page message
-                SmsCbConcatInfo concatInfo = new SmsCbConcatInfo(header, location);
-
-                // Try to find other pages of the same message
-                pdus = mSmsCbPageMap.get(concatInfo);
-
-                if (pdus == null) {
-                    // This is the first page of this message, make room for all
-                    // pages and keep until complete
-                    pdus = new byte[pageCount][];
-
-                    mSmsCbPageMap.put(concatInfo, pdus);
-                }
-
-                if (VDBG) log("pdus size=" + pdus.length);
-                // Page parameter is one-based
-                pdus[header.getPageIndex() - 1] = receivedPdu;
-
-                for (byte[] pdu : pdus) {
-                    if (pdu == null) {
-                        // Still missing pages, exit
-                        log("still missing pdu");
-                        return null;
-                    }
-                }
-
-                // Message complete, remove and dispatch
-                mSmsCbPageMap.remove(concatInfo);
-            } else {
-                // Single page message
-                pdus = new byte[1][];
-                pdus[0] = receivedPdu;
-            }
-
-            // Remove messages that are out of scope to prevent the map from
-            // growing indefinitely, containing incomplete messages that were
-            // never assembled
-            Iterator<SmsCbConcatInfo> iter = mSmsCbPageMap.keySet().iterator();
-
-            while (iter.hasNext()) {
-                SmsCbConcatInfo info = iter.next();
-
-                if (!info.matchesLocation(plmn, lac, cid)) {
-                    iter.remove();
-                }
-            }
-
-            return GsmSmsCbMessage.createSmsCbMessage(mContext, header, location, pdus,
-                mPhone.getPhoneId());
-
-        } catch (RuntimeException e) {
-            loge("Error in decoding SMS CB pdu", e);
-            return null;
-        }
-    }
-
-    private SmsCbHeader createSmsCbHeader(AsyncResult ar) {
-        try {
-            return new SmsCbHeader((byte[]) ar.result);
-        } catch (Exception ex) {
-            loge("Can't create SmsCbHeader, ex = " + ex.toString());
-            return null;
-        }
-    }
-
-    /**
-     * Holds all info about a message page needed to assemble a complete concatenated message.
-     */
-    private static final class SmsCbConcatInfo {
-
-        private final SmsCbHeader mHeader;
-        private final SmsCbLocation mLocation;
-
-        @UnsupportedAppUsage
-        SmsCbConcatInfo(SmsCbHeader header, SmsCbLocation location) {
-            mHeader = header;
-            mLocation = location;
-        }
-
-        @Override
-        public int hashCode() {
-            return (mHeader.getSerialNumber() * 31) + mLocation.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof SmsCbConcatInfo) {
-                SmsCbConcatInfo other = (SmsCbConcatInfo)obj;
-
-                // Two pages match if they have the same serial number (which includes the
-                // geographical scope and update number), and both pages belong to the same
-                // location (PLMN, plus LAC and CID if these are part of the geographical scope).
-                return mHeader.getSerialNumber() == other.mHeader.getSerialNumber()
-                        && mLocation.equals(other.mLocation);
-            }
-
-            return false;
-        }
-
-        /**
-         * Compare the location code for this message to the current location code. The match is
-         * relative to the geographical scope of the message, which determines whether the LAC
-         * and Cell ID are saved in mLocation or set to -1 to match all values.
-         *
-         * @param plmn the current PLMN
-         * @param lac the current Location Area (GSM) or Service Area (UMTS)
-         * @param cid the current Cell ID
-         * @return true if this message is valid for the current location; false otherwise
-         */
-        @UnsupportedAppUsage
-        public boolean matchesLocation(String plmn, int lac, int cid) {
-            return mLocation.isInLocationArea(plmn, lac, cid);
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
index 7b5dd0c..47f75ca 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.gsm;
 
 import android.app.Activity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -36,8 +37,6 @@
 import com.android.internal.telephony.VisualVoicemailSmsFilter;
 import com.android.internal.telephony.uicc.UsimServiceTable;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
 /**
  * This class broadcasts incoming SMS messages to interested apps after storing them in
  * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been
@@ -52,30 +51,22 @@
     private static final boolean TEST_MODE = SystemProperties.getInt("ro.debuggable", 0) == 1;
     private static final String TEST_ACTION = "com.android.internal.telephony.gsm"
             + ".TEST_TRIGGER_CELL_BROADCAST";
-    private static final String TOGGLE_CB_MODULE = "com.android.internal.telephony.gsm"
-            + ".TOGGLE_CB_MODULE";
 
     /**
      * Create a new GSM inbound SMS handler.
      */
     private GsmInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor,
             Phone phone) {
-        super("GsmInboundSmsHandler", context, storageMonitor, phone, null);
+        super("GsmInboundSmsHandler", context, storageMonitor, phone);
         phone.mCi.setOnNewGsmSms(getHandler(), EVENT_NEW_SMS, null);
         mDataDownloadHandler = new UsimDataDownloadHandler(phone.mCi, phone.getPhoneId());
-        if (sEnableCbModule) {
-            mCellBroadcastServiceManager.enable();
-        } else {
-            mCellBroadcastHandler = GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(context,
-                    phone);
-        }
+        mCellBroadcastServiceManager.enable();
 
         if (TEST_MODE) {
             if (sTestBroadcastReceiver == null) {
                 sTestBroadcastReceiver = new GsmCbTestBroadcastReceiver();
                 IntentFilter filter = new IntentFilter();
                 filter.addAction(TEST_ACTION);
-                filter.addAction(TOGGLE_CB_MODULE);
                 context.registerReceiver(sTestBroadcastReceiver, filter);
             }
         }
@@ -95,16 +86,11 @@
      * --es pdu_string  0000110011010D0A5BAE57CE770C531790E85C716CBF3044573065B9306757309707767 \
      * A751F30025F37304463FA308C306B5099304830664E0B30553044FF086C178C615E81FF09000000000000000 \
      * 0000000000000 --ei phone_id 0
-     *
-     * adb shell am broadcast -a com.android.internal.telephony.gsm.TOGGLE_CB_MODULE
-     *
-     * adb shell am broadcast -a com.android.internal.telephony.gsm.TOGGLE_CB_MODULE \
-     * --ez enable true
      */
     private class GsmCbTestBroadcastReceiver extends CbTestBroadcastReceiver {
 
         GsmCbTestBroadcastReceiver() {
-            super(TEST_ACTION, TOGGLE_CB_MODULE);
+            super(TEST_ACTION);
         }
 
         @Override
@@ -127,30 +113,7 @@
             }
             Message m = Message.obtain();
             AsyncResult.forMessage(m, smsPdu, null);
-            if (sEnableCbModule) {
-                mCellBroadcastServiceManager.sendGsmMessageToHandler(m);
-            } else {
-                m.setWhat(GsmCellBroadcastHandler.EVENT_NEW_SMS_MESSAGE);
-                mCellBroadcastHandler.sendMessage(m);
-            }
-        }
-
-        @Override
-        protected void handleToggleEnable() {
-            mPhone.mCi.unSetOnNewGsmBroadcastSms(mCellBroadcastHandler.getHandler());
-            mCellBroadcastServiceManager.enable();
-        }
-
-        @Override
-        protected void handleToggleDisable(Context context) {
-            mCellBroadcastServiceManager.disable();
-            if (mCellBroadcastHandler == null) {
-                mCellBroadcastHandler =
-                        GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(context,
-                                mPhone);
-            }
-            mPhone.mCi.setOnNewGsmBroadcastSms(mCellBroadcastHandler.getHandler(),
-                    GsmCellBroadcastHandler.EVENT_NEW_SMS_MESSAGE, null);
+            mCellBroadcastServiceManager.sendGsmMessageToHandler(m);
         }
     }
 
@@ -160,7 +123,6 @@
     @Override
     protected void onQuitting() {
         mPhone.mCi.unSetOnNewGsmSms(getHandler());
-        mCellBroadcastHandler.dispose();
 
         if (DBG) log("unregistered for 3GPP SMS");
         super.onQuitting();     // release wakelock
diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 01ba6ad..d8bc86c 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -27,6 +27,7 @@
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_SMS;
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.AsyncResult;
@@ -36,7 +37,6 @@
 import android.os.ResultReceiver;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.text.BidiFormatter;
 import android.text.SpannableStringBuilder;
 import android.text.TextDirectionHeuristics;
@@ -53,9 +53,8 @@
 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 dalvik.annotation.compat.UnsupportedAppUsage;
+import com.android.internal.telephony.util.ArrayUtils;
+import com.android.telephony.Rlog;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -381,12 +380,7 @@
                             isServiceClassVoiceorNone(ssData.serviceClass));
 
                     Rlog.d(LOG_TAG, "setVoiceCallForwardingFlag cffEnabled: " + cffEnabled);
-                    if (mIccRecords != null) {
-                        mPhone.setVoiceCallForwardingFlag(1, cffEnabled, null);
-                        Rlog.d(LOG_TAG, "setVoiceCallForwardingFlag done from SS Info.");
-                    } else {
-                        Rlog.e(LOG_TAG, "setVoiceCallForwardingFlag aborted. sim records is null.");
-                    }
+                    mPhone.setVoiceCallForwardingFlag(1, cffEnabled, null);
                 }
                 onSetComplete(null, new AsyncResult(null, ssData.cfInfo, ex));
                 break;
@@ -1210,9 +1204,7 @@
                 */
                 if ((ar.exception == null) && (msg.arg1 == 1)) {
                     boolean cffEnabled = (msg.arg2 == 1);
-                    if (mIccRecords != null) {
-                        mPhone.setVoiceCallForwardingFlag(1, cffEnabled, mDialingNumber);
-                    }
+                    mPhone.setVoiceCallForwardingFlag(1, cffEnabled, mDialingNumber);
                 }
 
                 onSetComplete(msg, ar);
@@ -1586,9 +1578,7 @@
                 (info.serviceClass & serviceClassMask)
                         == CommandsInterface.SERVICE_CLASS_VOICE) {
             boolean cffEnabled = (info.status == 1);
-            if (mIccRecords != null) {
-                mPhone.setVoiceCallForwardingFlag(1, cffEnabled, info.number);
-            }
+            mPhone.setVoiceCallForwardingFlag(1, cffEnabled, info.number);
         }
 
         return TextUtils.replace(template, sources, destinations);
@@ -1615,14 +1605,12 @@
 
             infos = (CallForwardInfo[]) ar.result;
 
-            if (infos.length == 0) {
+            if (infos == null || infos.length == 0) {
                 // Assume the default is not active
                 sb.append(mContext.getText(com.android.internal.R.string.serviceDisabled));
 
                 // Set unconditional CFF in SIM to false
-                if (mIccRecords != null) {
-                    mPhone.setVoiceCallForwardingFlag(1, false, null);
-                }
+                mPhone.setVoiceCallForwardingFlag(1, false, null);
             } else {
 
                 SpannableStringBuilder tb = new SpannableStringBuilder();
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 0e5d83f..e4044d2 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -18,10 +18,10 @@
 
 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.util.Pair;
 
@@ -38,8 +38,7 @@
 import com.android.internal.telephony.uicc.UiccCardApplication;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.util.SMSDispatcherUtil;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import com.android.telephony.Rlog;
 
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicReference;
@@ -185,8 +184,12 @@
 
         // if sms over IMS is not supported on data and voice is not available...
         if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
-            tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
-            return;
+        //In 5G case only Data Rat is reported.
+            if(mPhone.getServiceState().getRilDataRadioTechnology()
+                    != ServiceState.RIL_RADIO_TECHNOLOGY_NR) {
+                tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
+                return;
+            }
         }
 
         Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
diff --git a/src/java/com/android/internal/telephony/gsm/SimTlv.java b/src/java/com/android/internal/telephony/gsm/SimTlv.java
index 7df1f96..ee0d3ff 100644
--- a/src/java/com/android/internal/telephony/gsm/SimTlv.java
+++ b/src/java/com/android/internal/telephony/gsm/SimTlv.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.gsm;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * SIM Tag-Length-Value record
diff --git a/src/java/com/android/internal/telephony/gsm/SsData.java b/src/java/com/android/internal/telephony/gsm/SsData.java
index a5f67d8..41fa45e 100644
--- a/src/java/com/android/internal/telephony/gsm/SsData.java
+++ b/src/java/com/android/internal/telephony/gsm/SsData.java
@@ -19,11 +19,9 @@
 
 package com.android.internal.telephony.gsm;
 
-import android.telephony.Rlog;
 import com.android.internal.telephony.CallForwardInfo;
 import com.android.internal.telephony.GsmCdmaPhone;
-
-import java.util.ArrayList;
+import com.android.telephony.Rlog;
 
 /**
  * See also RIL_StkCcUnsolSsResponse in include/telephony/ril.h
diff --git a/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java b/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java
index 91cbbf0..5d08846 100644
--- a/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java
+++ b/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java
@@ -22,7 +22,6 @@
 import android.os.Message;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.SmsManager;
 
 import com.android.internal.telephony.CommandsInterface;
@@ -31,6 +30,7 @@
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.uicc.UsimServiceTable;
+import com.android.telephony.Rlog;
 
 /**
  * Handler for SMS-PP data download messages.
diff --git a/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
index a541459..f6fc069 100755
--- a/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -16,10 +16,10 @@
 
 package com.android.internal.telephony.gsm;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
-import android.telephony.Rlog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
@@ -28,8 +28,7 @@
 import com.android.internal.telephony.uicc.IccConstants;
 import com.android.internal.telephony.uicc.IccFileHandler;
 import com.android.internal.telephony.uicc.IccUtils;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 
diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java
index 2c3ed6d..5ff2536 100644
--- a/src/java/com/android/internal/telephony/ims/ImsResolver.java
+++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.ims;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -26,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -44,6 +46,7 @@
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.SparseArray;
@@ -51,25 +54,29 @@
 import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.telephony.PhoneConfigurationManager;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * Creates a list of ImsServices that are available to bind to based on the Device configuration
- * overlay value "config_ims_package" and Carrier Configuration value
- * "config_ims_package_override_string".
- * These ImsServices are then bound to in the following order:
+ * overlay values "config_ims_rcs_package" and "config_ims_mmtel_package" as well as Carrier
+ * Configuration value "config_ims_rcs_package_override_string" and
+ * "config_ims_mmtel_package_override_string".
+ * These ImsServices are then bound to in the following order for each mmtel and rcs feature:
  *
  * 1. Carrier Config defined override value per SIM.
  * 2. Device overlay default value (including no SIM case).
@@ -81,10 +88,14 @@
 public class ImsResolver implements ImsServiceController.ImsServiceControllerCallbacks {
 
     private static final String TAG = "ImsResolver";
+    private static final int GET_IMS_SERVICE_TIMEOUT_MS = 5000;
 
+    @VisibleForTesting
     public static final String METADATA_EMERGENCY_MMTEL_FEATURE =
             "android.telephony.ims.EMERGENCY_MMTEL_FEATURE";
+    @VisibleForTesting
     public static final String METADATA_MMTEL_FEATURE = "android.telephony.ims.MMTEL_FEATURE";
+    @VisibleForTesting
     public static final String METADATA_RCS_FEATURE = "android.telephony.ims.RCS_FEATURE";
     // Overrides the sanity permission check of android.permission.BIND_IMS_SERVICE for any
     // ImsService that is connecting to the platform.
@@ -99,17 +110,31 @@
     private static final int HANDLER_CONFIG_CHANGED = 2;
     // A query has been started for an ImsService to relay the features they support.
     private static final int HANDLER_START_DYNAMIC_FEATURE_QUERY = 3;
-    // A query to request ImsService features has completed or the ImsService has updated features.
+    // A dynamic query to request ImsService features has completed.
     private static final int HANDLER_DYNAMIC_FEATURE_CHANGE = 4;
     // Testing: Overrides the current configuration for ImsService binding
     private static final int HANDLER_OVERRIDE_IMS_SERVICE_CONFIG = 5;
     // Based on boot complete indication. When this happens, there may be ImsServices that are not
     // direct boot aware that need to be started.
     private static final int HANDLER_BOOT_COMPLETE = 6;
+    // Sent when the number of slots has dynamically changed on the device. We will need to
+    // resize available ImsServiceController slots and perform dynamic queries again.
+    private static final int HANDLER_MSIM_CONFIGURATION_CHANGE = 7;
 
     // Delay between dynamic ImsService queries.
     private static final int DELAY_DYNAMIC_QUERY_MS = 5000;
 
+    private static class OverrideConfig {
+        public final int slotId;
+        public final boolean isCarrierService;
+        public final Map<Integer, String> featureTypeToPackageMap;
+
+        OverrideConfig(int slotIndex, boolean isCarrier, Map<Integer, String> feature) {
+            slotId = slotIndex;
+            isCarrierService = isCarrier;
+            featureTypeToPackageMap = feature;
+        }
+    }
 
     /**
      * Stores information about an ImsService, including the package name, class name, and features
@@ -125,15 +150,13 @@
 
         // Map slotId->Feature
         private final HashSet<ImsFeatureConfiguration.FeatureSlotPair> mSupportedFeatures;
-        private final int mNumSlots;
 
-        public ImsServiceInfo(int numSlots) {
-            mNumSlots = numSlots;
+        public ImsServiceInfo() {
             mSupportedFeatures = new HashSet<>();
         }
 
-        void addFeatureForAllSlots(int feature) {
-            for (int i = 0; i < mNumSlots; i++) {
+        void addFeatureForAllSlots(int numSlots, int feature) {
+            for (int i = 0; i < numSlots; i++) {
                 mSupportedFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(i, feature));
             }
         }
@@ -144,7 +167,7 @@
         }
 
         @VisibleForTesting
-        public HashSet<ImsFeatureConfiguration.FeatureSlotPair> getSupportedFeatures() {
+        public Set<ImsFeatureConfiguration.FeatureSlotPair> getSupportedFeatures() {
             return mSupportedFeatures;
         }
 
@@ -359,37 +382,30 @@
                 }
             };
 
-    private ImsServiceControllerFactory mImsServiceControllerFactoryStaticBindingCompat =
-            new ImsServiceControllerFactory() {
-                @Override
-                public String getServiceInterface() {
-                    // The static method of binding does not use service interfaces.
-                    return null;
-                }
-
-                @Override
-                public ImsServiceController create(Context context, ComponentName componentName,
-                        ImsServiceController.ImsServiceControllerCallbacks callbacks) {
-                    return new ImsServiceControllerStaticCompat(context, componentName, callbacks);
-                }
-            };
-
     private ImsDynamicQueryManagerFactory mDynamicQueryManagerFactory =
             ImsServiceFeatureQueryManager::new;
 
     private final CarrierConfigManager mCarrierConfigManager;
     private final Context mContext;
+    // Special context created only for registering receivers for all users using UserHandle.ALL.
+    // The lifetime of a registered receiver is bounded by the lifetime of the context it's
+    // registered through, so we must retain the Context as long as we need the receiver to be
+    // active.
+    private final Context mReceiverContext;
     // Locks mBoundImsServicesByFeature only. Be careful to avoid deadlocks from
     // ImsServiceController callbacks.
     private final Object mBoundServicesLock = new Object();
-    private final int mNumSlots;
-    private final boolean mIsDynamicBinding;
-    // Package name of the default device service.
-    private String mDeviceService;
+    private int mNumSlots;
+    // Array index corresponds to slot, per slot there is a feature->package name mapping.
+    // should only be accessed from handler
+    private SparseArray<Map<Integer, String>> mCarrierServices;
+    // Package name of the default device services, Maps ImsFeature -> packageName.
+    // should only be accessed from handler
+    private Map<Integer, String> mDeviceServices;
     // Persistent Logging
     private final LocalLog mEventLog = new LocalLog(50);
 
-    // Synchronize all messages on a handler to ensure that the cache includes the most recent
+    // Synchronize all events on a handler to ensure that the cache includes the most recent
     // version of the installed ImsServices.
     private Handler mHandler = new Handler(Looper.getMainLooper(), (msg) -> {
         switch (msg.what) {
@@ -406,11 +422,17 @@
             case HANDLER_BOOT_COMPLETE: {
                 mEventLog.log("handling BOOT_COMPLETE");
                 // Re-evaluate bound services for all slots after requerying packagemanager
-                maybeAddedImsService(null);
+                maybeAddedImsService(null /*packageName*/);
                 break;
             }
             case HANDLER_CONFIG_CHANGED: {
                 int slotId = (Integer) msg.obj;
+                // If the msim config has changed and there is a residual event for an invalid slot,
+                // ignore.
+                if (slotId >= mNumSlots) {
+                    Log.w(TAG, "HANDLER_CONFIG_CHANGED for invalid slotid=" + slotId);
+                    break;
+                }
                 carrierConfigChanged(slotId);
                 break;
             }
@@ -429,39 +451,20 @@
                 break;
             }
             case HANDLER_OVERRIDE_IMS_SERVICE_CONFIG: {
-                int slotId = msg.arg1;
-                // arg2 will be equal to 1 if it is a carrier service.
-                boolean isCarrierImsService = (msg.arg2 == 1);
-                String packageName = (String) msg.obj;
-                if (isCarrierImsService) {
-                    Log.i(TAG, "overriding carrier ImsService - slot=" + slotId + " packageName="
-                            + packageName);
-                    overrideService(slotId, packageName);
+                OverrideConfig config = (OverrideConfig) msg.obj;
+                if (config.isCarrierService) {
+                    overrideCarrierService(config.slotId,
+                            config.featureTypeToPackageMap);
                 } else {
-                    Log.i(TAG, "overriding device ImsService -  packageName=" + packageName);
-                    mEventLog.log("overriding device ImsService with " + packageName);
-                    if (TextUtils.equals(mDeviceService, packageName)) {
-                        // No change in device service.
-                        break;
-                    }
-                    // Unbind from the previous ImsService before binding to the new one.
-                    unbindImsService(getImsServiceInfoFromCache(mDeviceService));
-                    mDeviceService = packageName;
-                    ImsServiceInfo deviceInfo = getImsServiceInfoFromCache(mDeviceService);
-                    if (deviceInfo == null) {
-                        // The package name is either "" or does not exist on the device.
-                        break;
-                    }
-                    if (deviceInfo.featureFromMetadata) {
-                        bindImsService(deviceInfo);
-                    } else {
-                        // newly added ImsServiceInfo that has not had features queried yet. Start
-                        // async bind and query features.
-                        scheduleQueryForFeatures(deviceInfo);
-                    }
+                    overrideDeviceService(config.featureTypeToPackageMap);
                 }
                 break;
             }
+            case HANDLER_MSIM_CONFIGURATION_CHANGE: {
+                AsyncResult result = (AsyncResult) msg.obj;
+                handleMsimConfigChange((Integer) result.result);
+                break;
+            }
             default:
                 return false;
         }
@@ -496,55 +499,48 @@
             };
 
     // Used during testing, overrides the carrier services while non-empty.
-    // Array index corresponds to slot Id associated with the service package name.
-    private String[] mOverrideServices;
-    // Array index corresponds to slot Id associated with the service package name.
-    private String[] mCarrierServices;
-    // List index corresponds to Slot Id, Maps ImsFeature.FEATURE->bound ImsServiceController
+    // Array index corresponds to slot, per slot there is a feature->package name mapping.
+    // should only be accessed from handler
+    private SparseArray<SparseArray<String>> mOverrideServices;
+    // Outer array index corresponds to Slot Id, Maps ImsFeature.FEATURE->bound ImsServiceController
     // Locked on mBoundServicesLock
-    private List<SparseArray<ImsServiceController>> mBoundImsServicesByFeature;
+    private SparseArray<SparseArray<ImsServiceController>> mBoundImsServicesByFeature;
     // not locked, only accessed on a handler thread.
+    // Tracks list of all installed ImsServices
     private Map<ComponentName, ImsServiceInfo> mInstalledServicesCache = new HashMap<>();
     // not locked, only accessed on a handler thread.
+    // Active ImsServiceControllers, which are bound to ImsServices.
     private Map<ComponentName, ImsServiceController> mActiveControllers = new HashMap<>();
-    // Only used as the Component name for legacy ImsServices that did not use dynamic binding.
-    private final ComponentName mStaticComponent;
     private ImsServiceFeatureQueryManager mFeatureQueryManager;
 
-    public ImsResolver(Context context, String defaultImsPackageName, int numSlots,
-            boolean isDynamicBinding) {
+    public ImsResolver(Context context, String defaultMmTelPackageName,
+            String defaultRcsPackageName, int numSlots) {
+        Log.i(TAG, "device MMTEL package: " + defaultMmTelPackageName + ", device RCS package:"
+                + defaultRcsPackageName);
         mContext = context;
-        mDeviceService = defaultImsPackageName;
         mNumSlots = numSlots;
-        mIsDynamicBinding = isDynamicBinding;
-        mStaticComponent = new ComponentName(mContext, ImsResolver.class);
-        if (!mIsDynamicBinding) {
-            Log.i(TAG, "ImsResolver initialized with static binding.");
-            mDeviceService = mStaticComponent.getPackageName();
-        }
+        mReceiverContext = context.createContextAsUser(UserHandle.ALL, 0 /*flags*/);
+
+        mCarrierServices = new SparseArray<>(mNumSlots);
+        mDeviceServices = new ArrayMap<>();
+        setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_EMERGENCY_MMTEL);
+        setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_MMTEL);
+        setDeviceConfiguration(defaultRcsPackageName, ImsFeature.FEATURE_RCS);
         mCarrierConfigManager = (CarrierConfigManager) mContext.getSystemService(
                 Context.CARRIER_CONFIG_SERVICE);
-        mCarrierServices = new String[numSlots];
-        mOverrideServices = new String[numSlots];
-        mBoundImsServicesByFeature = Stream.generate(SparseArray<ImsServiceController>::new)
-                .limit(mNumSlots).collect(Collectors.toList());
+        mOverrideServices = new SparseArray<>(0 /*initial size*/);
+        mBoundImsServicesByFeature = new SparseArray<>(mNumSlots);
 
-        // Only register for Package/CarrierConfig updates if dynamic binding.
-        if(mIsDynamicBinding) {
-            IntentFilter appChangedFilter = new IntentFilter();
-            appChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-            appChangedFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-            appChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-            appChangedFilter.addDataScheme("package");
-            context.registerReceiverAsUser(mAppChangedReceiver, UserHandle.ALL, appChangedFilter,
-                    null,
-                    null);
-
-            context.registerReceiver(mConfigChangedReceiver, new IntentFilter(
-                    CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
-            context.registerReceiver(mBootCompleted, new IntentFilter(
-                    Intent.ACTION_BOOT_COMPLETED));
-        }
+        IntentFilter appChangedFilter = new IntentFilter();
+        appChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        appChangedFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        appChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        appChangedFilter.addDataScheme("package");
+        mReceiverContext.registerReceiver(mAppChangedReceiver, appChangedFilter);
+        mReceiverContext.registerReceiver(mConfigChangedReceiver, new IntentFilter(
+                CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+        mReceiverContext.registerReceiver(mBootCompleted, new IntentFilter(
+                Intent.ACTION_BOOT_COMPLETED));
     }
 
     @VisibleForTesting
@@ -578,6 +574,8 @@
     public void initialize() {
         mEventLog.log("Initializing");
         Log.i(TAG, "Initializing cache.");
+        PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
+                HANDLER_MSIM_CONFIGURATION_CHANGE, null);
         mFeatureQueryManager = mDynamicQueryManagerFactory.create(mContext, mDynamicQueryListener);
 
         // This will get all services with the correct intent filter from PackageManager
@@ -590,20 +588,34 @@
         // Update the package names of the carrier ImsServices if they do not exist already and
         // possibly bind if carrier configs exist. Otherwise wait for CarrierConfigChanged
         // indication.
-        for (int i = 0; i < mNumSlots; i++) {
-            int subId = mSubscriptionManagerProxy.getSubId(i);
-            PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
-            if (config != null && mCarrierServices[i] == null) {
-                String newPackageName = config.getString(
-                        CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
+        bindCarrierServicesIfAvailable();
+    }
+
+    // Only start the bind if there is an existing Carrier Configuration. Otherwise, wait for
+    // carrier config changed.
+    private void bindCarrierServicesIfAvailable() {
+        boolean hasConfigChanged = false;
+        for (int slotId = 0; slotId < mNumSlots; slotId++) {
+            Map<Integer, String> featureMap = getImsPackageOverrideConfig(slotId);
+            for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) {
+                String newPackageName = featureMap.getOrDefault(f, "");
                 if (!TextUtils.isEmpty(newPackageName)) {
-                    mEventLog.log("Initializing: found carrier package.");
-                    updateBoundCarrierServices(i, newPackageName);
-                    Log.i(TAG, "Initializing, found package " + newPackageName + " on slot "
-                            + i);
+                    mEventLog.log("bindCarrierServicesIfAvailable - carrier package found: "
+                            + newPackageName + " on slot " + slotId);
+                    setCarrierConfiguredPackageName(newPackageName, slotId, f);
+                    ImsServiceInfo info = getImsServiceInfoFromCache(newPackageName);
+                    // We do not want to trigger feature configuration changes unless there is
+                    // already a valid carrier config change.
+                    if (info != null && info.featureFromMetadata) {
+                        hasConfigChanged = true;
+                    } else {
+                        // Config will change when this query completes
+                        scheduleQueryForFeatures(info);
+                    }
                 }
             }
         }
+        if (hasConfigChanged) calculateFeatureConfigurationChange();
     }
 
     /**
@@ -733,32 +745,112 @@
 
     // Used for testing only.
     public boolean overrideImsServiceConfiguration(int slotId, boolean isCarrierService,
-            String packageName) {
+            Map<Integer, String> featureConfig) {
         if (slotId < 0 || slotId >= mNumSlots) {
             Log.w(TAG, "overrideImsServiceConfiguration: invalid slotId!");
             return false;
         }
 
-        if (packageName == null) {
-            Log.w(TAG, "overrideImsServiceConfiguration: null packageName!");
-            return false;
-        }
-
-        // encode boolean to int for Message.
-        int carrierService = isCarrierService ? 1 : 0;
-        Message.obtain(mHandler, HANDLER_OVERRIDE_IMS_SERVICE_CONFIG, slotId, carrierService,
-                packageName).sendToTarget();
+        OverrideConfig overrideConfig = new OverrideConfig(slotId, isCarrierService, featureConfig);
+        Message.obtain(mHandler, HANDLER_OVERRIDE_IMS_SERVICE_CONFIG, overrideConfig)
+                .sendToTarget();
         return true;
     }
 
-    // used for testing only.
-    public String getImsServiceConfiguration(int slotId, boolean isCarrierService) {
+    // not synchronized, access through handler ONLY.
+    private String getDeviceConfiguration(@ImsFeature.FeatureType int featureType) {
+        return mDeviceServices.getOrDefault(featureType, "");
+    }
+
+    // not synchronized, access in handler ONLY.
+    private void setDeviceConfiguration(String name, @ImsFeature.FeatureType int featureType) {
+        mDeviceServices.put(featureType, name);
+    }
+
+    // not synchronized, access in handler ONLY.
+    private void setCarrierConfiguredPackageName(@NonNull String packageName, int slotId,
+            @ImsFeature.FeatureType int featureType) {
+        getCarrierConfiguredPackageNames(slotId).put(featureType, packageName);
+    }
+
+    // not synchronized, access in handler ONLY.
+    private @NonNull String getCarrierConfiguredPackageName(int slotId,
+            @ImsFeature.FeatureType int featureType) {
+        return getCarrierConfiguredPackageNames(slotId).getOrDefault(featureType, "");
+    }
+
+    // not synchronized, access in handler ONLY.
+    private @NonNull Map<Integer, String> getCarrierConfiguredPackageNames(int slotId) {
+        Map<Integer, String> carrierConfig = mCarrierServices.get(slotId);
+        if (carrierConfig == null) {
+            carrierConfig = new ArrayMap<>();
+            mCarrierServices.put(slotId, carrierConfig);
+        }
+        return carrierConfig;
+    }
+
+    // not synchronized, access in handler ONLY.
+    private void setOverridePackageName(@Nullable String packageName, int slotId,
+            @ImsFeature.FeatureType int featureType) {
+        getOverridePackageName(slotId).put(featureType, packageName);
+    }
+
+    // not synchronized, access in handler ONLY.
+    private @Nullable String getOverridePackageName(int slotId,
+            @ImsFeature.FeatureType int featureType) {
+        return getOverridePackageName(slotId).get(featureType);
+    }
+
+    // not synchronized, access in handler ONLY.
+    private @NonNull SparseArray<String> getOverridePackageName(int slotId) {
+        SparseArray<String> carrierConfig = mOverrideServices.get(slotId);
+        if (carrierConfig == null) {
+            carrierConfig = new SparseArray<>();
+            mOverrideServices.put(slotId, carrierConfig);
+        }
+        return carrierConfig;
+    }
+
+    /**
+     * @return true if there is a carrier configuration that exists for the slot & featureType pair
+     * and the cached carrier ImsService associated with the configuration also supports the
+     * requested ImsFeature type.
+     */
+    // not synchronized, access in handler ONLY.
+    private boolean doesCarrierConfigurationExist(int slotId,
+            @ImsFeature.FeatureType int featureType) {
+        String carrierPackage = getCarrierConfiguredPackageName(slotId, featureType);
+        if (TextUtils.isEmpty(carrierPackage)) {
+            return false;
+        }
+        // Config exists, but the carrier ImsService also needs to support this feature
+        ImsServiceInfo info = getImsServiceInfoFromCache(carrierPackage);
+        return info != null && info.getSupportedFeatures().stream().anyMatch(
+                feature -> feature.slotId == slotId && feature.featureType == featureType);
+    }
+
+    /**
+     * @return the package name of the ImsService with the requested configuration.
+     */
+    // used in shell commands queries during testing only.
+    public String getImsServiceConfiguration(int slotId, boolean isCarrierService,
+            @ImsFeature.FeatureType int featureType) {
         if (slotId < 0 || slotId >= mNumSlots) {
             Log.w(TAG, "getImsServiceConfiguration: invalid slotId!");
             return "";
         }
 
-        return isCarrierService ? mCarrierServices[slotId] : mDeviceService;
+        LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1);
+        // access the configuration on the handler.
+        mHandler.post(() -> result.offer(isCarrierService
+                ? getCarrierConfiguredPackageName(slotId, featureType) :
+                getDeviceConfiguration(featureType)));
+        try {
+            return result.poll(GET_IMS_SERVICE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "getImsServiceConfiguration: exception=" + e.getMessage());
+            return null;
+        }
     }
 
     private void putImsController(int slotId, int feature, ImsServiceController controller) {
@@ -772,7 +864,7 @@
             SparseArray<ImsServiceController> services = mBoundImsServicesByFeature.get(slotId);
             if (services == null) {
                 services = new SparseArray<>();
-                mBoundImsServicesByFeature.add(slotId, services);
+                mBoundImsServicesByFeature.put(slotId, services);
             }
             mEventLog.log("putImsController - [" + slotId + ", "
                     + ImsFeature.FEATURE_LOG_MAP.get(feature) + "] -> " + controller);
@@ -784,7 +876,7 @@
     }
 
     private ImsServiceController removeImsController(int slotId, int feature) {
-        if (slotId < 0 || slotId >= mNumSlots || feature <= ImsFeature.FEATURE_INVALID
+        if (slotId < 0 || feature <= ImsFeature.FEATURE_INVALID
                 || feature >= ImsFeature.FEATURE_MAX) {
             Log.w(TAG, "removeImsController received invalid parameters - slot: " + slotId
                     + ", feature: " + feature);
@@ -814,7 +906,9 @@
     private void maybeAddedImsService(String packageName) {
         Log.d(TAG, "maybeAddedImsService, packageName: " + packageName);
         List<ImsServiceInfo> infos = getImsServiceInfo(packageName);
-        List<ImsServiceInfo> newlyAddedInfos = new ArrayList<>();
+        // Wait until all ImsServiceInfo is cached before calling
+        // calculateFeatureConfigurationChange to reduce churn.
+        boolean requiresCalculation = false;
         for (ImsServiceInfo info : infos) {
             // Checking to see if the ComponentName is the same, so we can update the supported
             // features. Will only be one (if it exists), since it is a set.
@@ -832,7 +926,7 @@
                             + info);
                     // update features in the cache
                     match.replaceFeatures(info.getSupportedFeatures());
-                    updateImsServiceFeatures(info);
+                    requiresCalculation = true;
                 } else {
                     mEventLog.log("maybeAddedImsService - scheduling query for " + info);
                     // start a query to get ImsService features
@@ -843,7 +937,7 @@
                 mEventLog.log("maybeAddedImsService - adding new ImsService: " + info);
                 mInstalledServicesCache.put(info.name, info);
                 if (info.featureFromMetadata) {
-                    newlyAddedInfos.add(info);
+                    requiresCalculation = true;
                 } else {
                     // newly added ImsServiceInfo that has not had features queried yet. Start async
                     // bind and query features.
@@ -851,20 +945,7 @@
                 }
             }
         }
-        // Loop through the newly created ServiceInfos in a separate loop to make sure the cache
-        // is fully updated.
-        for (ImsServiceInfo info : newlyAddedInfos) {
-            if (isActiveCarrierService(info)) {
-                // New ImsService is registered to active carrier services and must be newly
-                // bound.
-                bindImsService(info);
-                // Update existing device service features
-                updateImsServiceFeatures(getImsServiceInfoFromCache(mDeviceService));
-            } else if (isDeviceService(info)) {
-                // New ImsService is registered as device default and must be newly bound.
-                bindImsService(info);
-            }
-        }
+        if (requiresCalculation) calculateFeatureConfigurationChange();
     }
 
     // Remove the ImsService from the cache. This may have been due to the ImsService being removed
@@ -877,35 +958,27 @@
             mEventLog.log("maybeRemovedImsService - removing ImsService: " + match);
             Log.i(TAG, "Removing ImsService: " + match.name);
             unbindImsService(match);
-            updateImsServiceFeatures(getImsServiceInfoFromCache(mDeviceService));
+            calculateFeatureConfigurationChange();
             return true;
         }
         return false;
     }
 
-    // Returns true if the CarrierConfig that has been loaded includes this ImsServiceInfo
-    // package name.
-    // Called from Handler ONLY
-    private boolean isActiveCarrierService(ImsServiceInfo info) {
-        for (int i = 0; i < mNumSlots; i++) {
-            if (TextUtils.equals(mCarrierServices[i], info.name.getPackageName())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private boolean isDeviceService(ImsServiceInfo info) {
-        return TextUtils.equals(mDeviceService, info.name.getPackageName());
+        if (info == null) return false;
+        return mDeviceServices.containsValue(info.name.getPackageName());
     }
 
-    private int getSlotForActiveCarrierService(ImsServiceInfo info) {
+    private List<Integer> getSlotsForActiveCarrierService(ImsServiceInfo info) {
+        if (info == null) return Collections.emptyList();
+        List<Integer> slots = new ArrayList<>(mNumSlots);
         for (int i = 0; i < mNumSlots; i++) {
-            if (TextUtils.equals(mCarrierServices[i], info.name.getPackageName())) {
-                return i;
+            if (!TextUtils.isEmpty(getCarrierConfiguredPackageNames(i).values().stream()
+                    .filter(e -> e.equals(info.name.getPackageName())).findAny().orElse(""))) {
+                slots.add(i);
             }
         }
-        return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+        return slots;
     }
 
     private ImsServiceController getControllerByServiceInfo(
@@ -927,64 +1000,15 @@
         return searchMap.get(matchValue);
     }
 
-    // Creates new features in active ImsServices and removes obsolete cached features. If
-    // cachedInfo == null, then newInfo is assumed to be a new ImsService and will have all features
-    // created.
-    private void updateImsServiceFeatures(ImsServiceInfo newInfo) {
-        if (newInfo == null) {
-            return;
-        }
-        ImsServiceController controller = getControllerByServiceInfo(mActiveControllers, newInfo);
-        // Will return zero if these features are overridden or it should not currently have any
-        // features because it is not carrier/device.
-        HashSet<ImsFeatureConfiguration.FeatureSlotPair> features =
-                calculateFeaturesToCreate(newInfo);
-        if (shouldFeaturesCauseBind(features)) {
-            try {
-                if (controller != null) {
-                    Log.i(TAG, "Updating features for ImsService: "
-                            + controller.getComponentName());
-                    Log.d(TAG, "Updating Features - New Features: " + features);
-                    controller.changeImsServiceFeatures(features);
-                } else {
-                    Log.i(TAG, "updateImsServiceFeatures: unbound with active features, binding");
-                    bindImsServiceWithFeatures(newInfo, features);
-                }
-                // If the carrier service features have changed, the device features will also
-                // need to be recalculated.
-                if (isActiveCarrierService(newInfo)
-                        // Prevent infinite recursion from bad behavior
-                        && !TextUtils.equals(newInfo.name.getPackageName(), mDeviceService)) {
-                    Log.i(TAG, "Updating device default");
-                    updateImsServiceFeatures(getImsServiceInfoFromCache(mDeviceService));
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "updateImsServiceFeatures: Remote Exception: " + e.getMessage());
-            }
-        // Don't stay bound if the ImsService is providing no features.
-        } else if (controller != null) {
-            Log.i(TAG, "Unbinding: features = 0 for ImsService: " + controller.getComponentName());
-            unbindImsService(newInfo);
-        }
-    }
-
-    // Bind to an ImsService and wait for the service to be connected to create ImsFeatures.
-    private void bindImsService(ImsServiceInfo info) {
-        if (info == null) {
-            return;
-        }
-        HashSet<ImsFeatureConfiguration.FeatureSlotPair> features = calculateFeaturesToCreate(info);
-        bindImsServiceWithFeatures(info, features);
-    }
-
     private void bindImsServiceWithFeatures(ImsServiceInfo info,
-            HashSet<ImsFeatureConfiguration.FeatureSlotPair> features) {
+            Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
         // Only bind if there are features that will be created by the service.
         if (shouldFeaturesCauseBind(features)) {
             // Check to see if an active controller already exists
             ImsServiceController controller = getControllerByServiceInfo(mActiveControllers, info);
             if (controller != null) {
-                Log.i(TAG, "ImsService connection exists, updating features " + features);
+                Log.i(TAG, "ImsService connection exists for " + info.name + ", updating features "
+                        + features);
                 try {
                     controller.changeImsServiceFeatures(features);
                     // Features have been set, there was an error adding/removing. When the
@@ -1030,36 +1054,27 @@
     private HashSet<ImsFeatureConfiguration.FeatureSlotPair> calculateFeaturesToCreate(
             ImsServiceInfo info) {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> imsFeaturesBySlot = new HashSet<>();
-        // Check if the info is a carrier service
-        int slotId = getSlotForActiveCarrierService(info);
-        if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+        List<Integer> slots = getSlotsForActiveCarrierService(info);
+        if (!slots.isEmpty()) {
+            // There is an active carrier config associated with this. Return with the ImsService's
+            // supported features that are also within the carrier configuration
             imsFeaturesBySlot.addAll(info.getSupportedFeatures().stream()
-                    // Match slotId with feature slotId.
-                    .filter(feature -> slotId == feature.slotId)
+                    .filter(feature -> info.name.getPackageName().equals(
+                            getCarrierConfiguredPackageName(feature.slotId, feature.featureType)))
                     .collect(Collectors.toList()));
-        } else if (isDeviceService(info)) {
-            // For all slots that are not currently using a carrier ImsService, enable all features
-            // for the device default.
-            for (int i = 0; i < mNumSlots; i++) {
-                final int currSlotId = i;
-                ImsServiceInfo carrierImsInfo = getImsServiceInfoFromCache(mCarrierServices[i]);
-                if (carrierImsInfo == null) {
-                    // No Carrier override, add all features for this slot
-                    imsFeaturesBySlot.addAll(info.getSupportedFeatures().stream()
-                            .filter(feature -> currSlotId == feature.slotId)
-                            .collect(Collectors.toList()));
-                } else {
-                    // Add all features to the device service that are not currently covered by
-                    // the carrier ImsService.
-                    HashSet<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatures =
-                            new HashSet<>(info.getSupportedFeatures());
-                    deviceFeatures.removeAll(carrierImsInfo.getSupportedFeatures());
-                    // only add features for current slot
-                    imsFeaturesBySlot.addAll(deviceFeatures.stream()
-                            .filter(feature -> currSlotId == feature.slotId).collect(
-                            Collectors.toList()));
-                }
-            }
+            return imsFeaturesBySlot;
+        }
+        if (isDeviceService(info)) {
+            imsFeaturesBySlot.addAll(info.getSupportedFeatures().stream()
+                    // only allow supported features that are also set for this package as the
+                    // device configuration.
+                    .filter(feature -> info.name.getPackageName().equals(
+                            getDeviceConfiguration(feature.featureType)))
+                    // filter out any separate carrier configuration, since that feature is handled
+                    // by the carrier ImsService.
+                    .filter(feature -> !doesCarrierConfigurationExist(feature.slotId,
+                            feature.featureType))
+                    .collect(Collectors.toList()));
         }
         return imsFeaturesBySlot;
     }
@@ -1115,30 +1130,51 @@
      * @return true if MMTEL or RCS features are present, false if they are not or only
      * EMERGENCY_MMTEL is specified.
      */
-    private boolean shouldFeaturesCauseBind(
-            HashSet<ImsFeatureConfiguration.FeatureSlotPair> features) {
+    private boolean shouldFeaturesCauseBind(Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
         long bindableFeatures = features.stream()
                 // remove all emergency features
                 .filter(f -> f.featureType != ImsFeature.FEATURE_EMERGENCY_MMTEL).count();
         return bindableFeatures > 0;
     }
 
-    // Possibly rebind to another ImsService for testing.
+    // Possibly rebind to another ImsService for testing carrier ImsServices.
     // Called from the handler ONLY
-    private void overrideService(int slotId, String newPackageName) {
-        mEventLog.log("overriding carrier ImsService to " + newPackageName
-                + " on slot " + slotId);
-        if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            // not specified, replace package on all slots.
-            for (int i = 0; i < mNumSlots; i++) {
-                mOverrideServices[i] = newPackageName;
-                updateBoundCarrierServices(i, newPackageName);
-            }
-        } else {
-            mOverrideServices[slotId] = newPackageName;
-            updateBoundCarrierServices(slotId, newPackageName);
+    private void overrideCarrierService(int slotId, Map<Integer, String> featureMap) {
+        for (Integer featureType : featureMap.keySet()) {
+            String overridePackageName = featureMap.get(featureType);
+            mEventLog.log("overriding carrier ImsService to " + overridePackageName
+                    + " on slot " + slotId + " for feature "
+                    + ImsFeature.FEATURE_LOG_MAP.getOrDefault(featureType, "invalid"));
+            setOverridePackageName(overridePackageName, slotId, featureType);
         }
+        updateBoundServices(slotId, Collections.emptyMap());
+    }
 
+    // Possibly rebind to another ImsService for testing carrier ImsServices.
+    // Called from the handler ONLY
+    private void overrideDeviceService(Map<Integer, String> featureMap) {
+        boolean requiresRecalc = false;
+        for (Integer featureType : featureMap.keySet()) {
+            String overridePackageName = featureMap.get(featureType);
+            mEventLog.log("overriding device ImsService to " + overridePackageName + " for feature "
+                    + ImsFeature.FEATURE_LOG_MAP.getOrDefault(featureType, "invalid"));
+            String oldPackageName = getDeviceConfiguration(featureType);
+            if (!TextUtils.equals(oldPackageName, overridePackageName)) {
+                Log.i(TAG, "overrideDeviceService - device package changed (override): "
+                        + oldPackageName + " -> " + overridePackageName);
+                mEventLog.log("overrideDeviceService - device package changed (override): "
+                        + oldPackageName + " -> " + overridePackageName);
+                setDeviceConfiguration(overridePackageName, featureType);
+                ImsServiceInfo info = getImsServiceInfoFromCache(overridePackageName);
+                if (info == null || info.featureFromMetadata) {
+                    requiresRecalc = true;
+                } else {
+                    // Config will change when this query completes
+                    scheduleQueryForFeatures(info);
+                }
+            }
+        }
+        if (requiresRecalc) calculateFeatureConfigurationChange();
     }
 
     // Called from handler ONLY.
@@ -1146,74 +1182,76 @@
         if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
             // not specified, update carrier override cache and possibly rebind on all slots.
             for (int i = 0; i < mNumSlots; i++) {
-                updateBoundCarrierServices(i, getImsPackageOverrideConfig(i));
+                updateBoundServices(i, getImsPackageOverrideConfig(i));
             }
         }
-        updateBoundCarrierServices(slotId, getImsPackageOverrideConfig(slotId));
+        updateBoundServices(slotId, getImsPackageOverrideConfig(slotId));
     }
 
-    private String getImsPackageOverrideConfig(int slotId) {
-        int subId = mSubscriptionManagerProxy.getSubId(slotId);
-        PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
-        if (config == null) return null;
-        return config.getString(CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
-    }
-
-    /**
-     * Use the slotId specified to update the carrier override cache with the new package name.
-     * If it has changed, trigger an unbind from the old service kick off the process to recalculate
-     * features supported on the new service.
-     */
-    private void updateBoundCarrierServices(int slotId, String newPackageName) {
-        if (slotId > SubscriptionManager.INVALID_SIM_SLOT_INDEX && slotId < mNumSlots) {
-            String overridePackageName = mOverrideServices[slotId];
-            String oldPackageName = mCarrierServices[slotId];
+    private void updateBoundServices(int slotId, Map<Integer, String> featureMap) {
+        if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlots) {
+            return;
+        }
+        boolean hasConfigChanged = false;
+        for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) {
+            String overridePackageName = getOverridePackageName(slotId, f);
+            String oldPackageName = getCarrierConfiguredPackageName(slotId, f);
+            String newPackageName = featureMap.getOrDefault(f, "");
             if (!TextUtils.isEmpty(overridePackageName)) {
-                // Do not allow carrier config changes to change the override package while it is
-                // in effect.
-                Log.i(TAG, "CarrierConfig change ignored for " + newPackageName + " while override"
-                        + " is in effect for " + overridePackageName);
+                // Do not allow carrier config changes to change the override package while it
+                // is in effect.
+                Log.i(TAG, String.format("updateBoundServices: overriding %s with %s for feature"
+                                + " %s on slot %d",
+                        TextUtils.isEmpty(newPackageName) ? "(none)" : newPackageName,
+                        overridePackageName,
+                        ImsFeature.FEATURE_LOG_MAP.getOrDefault(f, "invalid"), slotId));
                 newPackageName = overridePackageName;
             }
-            mCarrierServices[slotId] = newPackageName;
-            if (!TextUtils.equals(newPackageName, oldPackageName)) {
-                Log.i(TAG, "Carrier Config updated, binding new ImsService");
-                mEventLog.log("updateBoundCarrierServices - carrier package changed: "
-                        + oldPackageName + " -> " + newPackageName + " on slot " + slotId);
-                // Unbind old ImsService, not needed anymore
-                // ImsService is retrieved from the cache. If the cache hasn't been populated yet,
-                // the calls to unbind/bind will fail (intended during initial start up).
-                unbindImsService(getImsServiceInfoFromCache(oldPackageName));
-            }
-            ImsServiceInfo newInfo = getImsServiceInfoFromCache(newPackageName);
-            // if there is no carrier ImsService, newInfo is null. This we still want to update
-            // bindings for device ImsService to pick up the missing features.
-            if (newInfo == null || newInfo.featureFromMetadata) {
-                mEventLog.log("updateBoundCarrierServices - recalculating bindings "
-                        + (newInfo != null ? newInfo : "for device"));
-                bindImsService(newInfo);
-                // Recalculate the device ImsService features to reflect changes.
-                updateImsServiceFeatures(getImsServiceInfoFromCache(mDeviceService));
+            mEventLog.log("updateBoundServices - carrier package changed: "
+                    + oldPackageName + " -> " + newPackageName + " on slot " + slotId);
+            setCarrierConfiguredPackageName(newPackageName, slotId, f);
+            // Carrier config may have not changed, but we still want to kick off a recalculation
+            // in case there has been a change to the supported device features.
+            ImsServiceInfo info = getImsServiceInfoFromCache(newPackageName);
+            if (info == null || info.featureFromMetadata) {
+                hasConfigChanged = true;
             } else {
-                // ImsServiceInfo that has not had features queried yet. Start async
-                // bind and query features.
-                mEventLog.log("updateBoundCarrierServices - scheduling feature query for "
-                        + newInfo);
-                scheduleQueryForFeatures(newInfo);
+                // Config will change when this query completes
+                scheduleQueryForFeatures(info);
             }
         }
+        if (hasConfigChanged) calculateFeatureConfigurationChange();
+    }
+
+    private @NonNull Map<Integer, String> getImsPackageOverrideConfig(int slotId) {
+        int subId = mSubscriptionManagerProxy.getSubId(slotId);
+        PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+        if (config == null) return Collections.emptyMap();
+        String packageNameMmTel = config.getString(
+                CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
+        // Set the config equal for the deprecated key.
+        String packageNameRcs = packageNameMmTel;
+        packageNameMmTel = config.getString(
+                CarrierConfigManager.KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING,
+                packageNameMmTel);
+        packageNameRcs = config.getString(
+                CarrierConfigManager.KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING, packageNameRcs);
+        Map<Integer, String> result = new ArrayMap<>();
+        if (!TextUtils.isEmpty(packageNameMmTel)) {
+            result.put(ImsFeature.FEATURE_EMERGENCY_MMTEL, packageNameMmTel);
+            result.put(ImsFeature.FEATURE_MMTEL, packageNameMmTel);
+        }
+        if (!TextUtils.isEmpty(packageNameRcs)) {
+            result.put(ImsFeature.FEATURE_RCS, packageNameRcs);
+        }
+        return result;
     }
 
     /**
      * Schedules a query for dynamic ImsService features.
      */
     private void scheduleQueryForFeatures(ImsServiceInfo service, int delayMs) {
-        // if not current device/carrier service, don't perform query. If this changes, this method
-        // will be called again.
-        if (!isDeviceService(service) && getSlotForActiveCarrierService(service)
-                == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            Log.i(TAG, "scheduleQueryForFeatures: skipping query for ImsService that is not"
-                    + " set as carrier/device ImsService.");
+        if (service == null) {
             return;
         }
         Message msg = Message.obtain(mHandler, HANDLER_START_DYNAMIC_FEATURE_QUERY, service);
@@ -1251,8 +1289,72 @@
         mHandler.obtainMessage(HANDLER_DYNAMIC_FEATURE_CHANGE, args).sendToTarget();
     }
 
+    private void handleMsimConfigChange(Integer newNumSlots) {
+        int oldLen = mNumSlots;
+        if (oldLen == newNumSlots) {
+            return;
+        }
+        mNumSlots = newNumSlots;
+        Log.i(TAG, "handleMsimConfigChange: oldLen=" + oldLen + ", newLen=" + newNumSlots);
+        mEventLog.log("MSIM config change: " + oldLen + " -> " + newNumSlots);
+        if (newNumSlots < oldLen) {
+            // we need to trim data structures that use slots, however mBoundImsServicesByFeature
+            // will be updated by ImsServiceController changing to remove features on old slots.
+            // start at the index of the new highest slot + 1.
+            for (int oldSlot = newNumSlots; oldSlot < oldLen; oldSlot++) {
+                // First clear old carrier configs
+                Map<Integer, String> carrierConfigs = getCarrierConfiguredPackageNames(oldSlot);
+                for (Integer feature : carrierConfigs.keySet()) {
+                    setCarrierConfiguredPackageName("", oldSlot, feature);
+                }
+                // next clear old overrides
+                SparseArray<String> overrideConfigs = getOverridePackageName(oldSlot);
+                for (int i = 0; i < overrideConfigs.size(); i++) {
+                    int feature = overrideConfigs.keyAt(i);
+                    setOverridePackageName("", oldSlot, feature);
+                }
+            }
+        }
+        // Get the new config for each ImsService. For manifest queries, this will update the
+        // number of slots.
+        // This will get all services with the correct intent filter from PackageManager
+        List<ImsServiceInfo> infos = getImsServiceInfo(null);
+        for (ImsServiceInfo info : infos) {
+            ImsServiceInfo cachedInfo = mInstalledServicesCache.get(info.name);
+            if (cachedInfo != null) {
+                if (info.featureFromMetadata) {
+                    cachedInfo.replaceFeatures(info.getSupportedFeatures());
+                } else {
+                    // Remove features that are no longer supported by the device configuration.
+                    cachedInfo.getSupportedFeatures()
+                            .removeIf(filter -> filter.slotId >= newNumSlots);
+                }
+            } else {
+                // This is unexpected, put the new service on the queue to be added
+                mEventLog.log("handleMsimConfigChange: detected untracked service - " + info);
+                Log.w(TAG, "handleMsimConfigChange: detected untracked package, queueing to add "
+                        + info);
+                mHandler.obtainMessage(HANDLER_ADD_PACKAGE,
+                        info.name.getPackageName()).sendToTarget();
+            }
+        }
+
+        if (newNumSlots < oldLen) {
+            // A CarrierConfigChange will happen for the new slot, so only recalculate if there are
+            // less new slots because we need to remove the old capabilities.
+            calculateFeatureConfigurationChange();
+        }
+    }
+
     // Starts a dynamic query. Called from handler ONLY.
     private void startDynamicQuery(ImsServiceInfo service) {
+        // if not current device/carrier service, don't perform query. If this changes, this method
+        // will be called again.
+        if (!isDeviceService(service) && getSlotsForActiveCarrierService(service).isEmpty()) {
+            Log.i(TAG, "scheduleQueryForFeatures: skipping query for ImsService that is not"
+                    + " set as carrier/device ImsService.");
+            return;
+        }
         mEventLog.log("startDynamicQuery - starting query for " + service);
         boolean queryStarted = mFeatureQueryManager.startQuery(service.name,
                 service.controllerFactory.getServiceInterface());
@@ -1271,23 +1373,46 @@
             Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
         ImsServiceInfo service = getImsServiceInfoFromCache(name.getPackageName());
         if (service == null) {
-            Log.w(TAG, "handleFeaturesChanged: Couldn't find cached info for name: "
+            Log.w(TAG, "dynamicQueryComplete: Couldn't find cached info for name: "
                     + name);
             return;
         }
-        mEventLog.log("dynamicQueryComplete for package " + name + ", features: "
+        mEventLog.log("dynamicQueryComplete: for package " + name + ", features: "
                 + printFeatures(service.getSupportedFeatures()) + " -> " + printFeatures(features));
+        sanitizeFeatureConfig(features);
         // Add features to service
         service.replaceFeatures(features);
-        if (isActiveCarrierService(service)) {
-            // New ImsService is registered to active carrier services and must be newly
-            // bound.
-            bindImsService(service);
-            // Update existing device service features
-            updateImsServiceFeatures(getImsServiceInfoFromCache(mDeviceService));
-        } else if (isDeviceService(service)) {
-            // New ImsService is registered as device default and must be newly bound.
-            bindImsService(service);
+        // Wait until all queries have completed before changing the configuration to reduce churn.
+        if (!mFeatureQueryManager.isQueryInProgress()) {
+            calculateFeatureConfigurationChange();
+        }
+    }
+
+    /**
+     * Ensure the feature includes MMTEL when it supports EMERGENCY_MMTEL, if not, remove.
+     */
+    private void sanitizeFeatureConfig(Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
+        Set<ImsFeatureConfiguration.FeatureSlotPair> emergencyMmtelFeatures = features.stream()
+                .filter(feature -> feature.featureType == ImsFeature.FEATURE_EMERGENCY_MMTEL)
+                .collect(Collectors.toSet());
+        for (ImsFeatureConfiguration.FeatureSlotPair feature : emergencyMmtelFeatures) {
+            if (!features.contains(new ImsFeatureConfiguration.FeatureSlotPair(feature.slotId,
+                    ImsFeature.FEATURE_MMTEL))) {
+                features.remove(feature);
+            }
+        }
+    }
+
+    // Calculate the new configuration for the bound ImsServices.
+    // Should ONLY be called from the handler.
+    private void calculateFeatureConfigurationChange() {
+        for (ImsServiceInfo info : mInstalledServicesCache.values()) {
+            Set<ImsFeatureConfiguration.FeatureSlotPair> features = calculateFeaturesToCreate(info);
+            if (shouldFeaturesCauseBind(features)) {
+                bindImsServiceWithFeatures(info, features);
+            } else {
+                unbindImsService(info);
+            }
         }
     }
 
@@ -1328,27 +1453,10 @@
     // get all packages that support ImsServices.
     private List<ImsServiceInfo> getImsServiceInfo(String packageName) {
         List<ImsServiceInfo> infos = new ArrayList<>();
-        if (!mIsDynamicBinding) {
-            // always return the same ImsService info.
-            infos.addAll(getStaticImsService());
-        } else {
-            // Search for Current ImsService implementations
-            infos.addAll(searchForImsServices(packageName, mImsServiceControllerFactory));
-            // Search for compat ImsService Implementations
-            infos.addAll(searchForImsServices(packageName, mImsServiceControllerFactoryCompat));
-        }
-        return infos;
-    }
-
-    private List<ImsServiceInfo> getStaticImsService() {
-        List<ImsServiceInfo> infos = new ArrayList<>();
-
-        ImsServiceInfo info = new ImsServiceInfo(mNumSlots);
-        info.name = mStaticComponent;
-        info.controllerFactory = mImsServiceControllerFactoryStaticBindingCompat;
-        info.addFeatureForAllSlots(ImsFeature.FEATURE_EMERGENCY_MMTEL);
-        info.addFeatureForAllSlots(ImsFeature.FEATURE_MMTEL);
-        infos.add(info);
+        // Search for Current ImsService implementations
+        infos.addAll(searchForImsServices(packageName, mImsServiceControllerFactory));
+        // Search for compat ImsService Implementations
+        infos.addAll(searchForImsServices(packageName, mImsServiceControllerFactoryCompat));
         return infos;
     }
 
@@ -1363,11 +1471,11 @@
         for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
                 serviceIntent,
                 PackageManager.GET_META_DATA,
-                UserHandle.getUserHandleForUid(mContext.getUserId()))) {
+                UserHandle.getUserHandleForUid(UserHandle.myUserId()))) {
             ServiceInfo serviceInfo = entry.serviceInfo;
 
             if (serviceInfo != null) {
-                ImsServiceInfo info = new ImsServiceInfo(mNumSlots);
+                ImsServiceInfo info = new ImsServiceInfo();
                 info.name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
                 info.controllerFactory = controllerFactory;
 
@@ -1379,15 +1487,17 @@
                 if (isDeviceService(info)
                         || mImsServiceControllerFactoryCompat == controllerFactory) {
                     if (serviceInfo.metaData != null) {
-                        if (serviceInfo.metaData.getBoolean(METADATA_EMERGENCY_MMTEL_FEATURE,
-                                false)) {
-                            info.addFeatureForAllSlots(ImsFeature.FEATURE_EMERGENCY_MMTEL);
-                        }
                         if (serviceInfo.metaData.getBoolean(METADATA_MMTEL_FEATURE, false)) {
-                            info.addFeatureForAllSlots(ImsFeature.FEATURE_MMTEL);
+                            info.addFeatureForAllSlots(mNumSlots, ImsFeature.FEATURE_MMTEL);
+                            // only allow FEATURE_EMERGENCY_MMTEL if FEATURE_MMTEL is defined.
+                            if (serviceInfo.metaData.getBoolean(METADATA_EMERGENCY_MMTEL_FEATURE,
+                                    false)) {
+                                info.addFeatureForAllSlots(mNumSlots,
+                                        ImsFeature.FEATURE_EMERGENCY_MMTEL);
+                            }
                         }
                         if (serviceInfo.metaData.getBoolean(METADATA_RCS_FEATURE, false)) {
-                            info.addFeatureForAllSlots(ImsFeature.FEATURE_RCS);
+                            info.addFeatureForAllSlots(mNumSlots, ImsFeature.FEATURE_RCS);
                         }
                     }
                     // Only dynamic query if we are not a compat version of ImsService and the
@@ -1425,14 +1535,31 @@
         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
         pw.println("ImsResolver:");
         pw.increaseIndent();
-        pw.println("mIsDynamicBinding = " + mIsDynamicBinding);
-        pw.println("mDeviceService = " + mDeviceService);
-        pw.println("mCarrierServices: ");
+        pw.println("Configurations:");
         pw.increaseIndent();
-        for (String s : mCarrierServices) {
-            pw.println(s);
+        pw.println("Device:");
+        pw.increaseIndent();
+        for (Integer i : mDeviceServices.keySet()) {
+            pw.println(ImsFeature.FEATURE_LOG_MAP.get(i) + " -> " + mDeviceServices.get(i));
         }
         pw.decreaseIndent();
+        pw.println("Carrier: ");
+        pw.increaseIndent();
+        for (int i = 0; i < mNumSlots; i++) {
+            for (int j = 0; j < MmTelFeature.FEATURE_MAX; j++) {
+                pw.print("slot=");
+                pw.print(i);
+                pw.print(", feature=");
+                pw.print(ImsFeature.FEATURE_LOG_MAP.getOrDefault(j, "?"));
+                pw.println(": ");
+                pw.increaseIndent();
+                String name = getCarrierConfiguredPackageName(i, j);
+                pw.println(TextUtils.isEmpty(name) ? "none" : name);
+                pw.decreaseIndent();
+            }
+        }
+        pw.decreaseIndent();
+        pw.decreaseIndent();
         pw.println("Bound Features:");
         pw.increaseIndent();
         for (int i = 0; i < mNumSlots; i++) {
@@ -1440,7 +1567,7 @@
                 pw.print("slot=");
                 pw.print(i);
                 pw.print(", feature=");
-                pw.print(MmTelFeature.FEATURE_LOG_MAP.getOrDefault(j, "?"));
+                pw.print(ImsFeature.FEATURE_LOG_MAP.getOrDefault(j, "?"));
                 pw.println(": ");
                 pw.increaseIndent();
                 ImsServiceController c = getImsServiceController(i, j);
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
index af26eba..967152d 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
@@ -27,6 +27,7 @@
 import android.os.IInterface;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.telephony.ims.ImsService;
 import android.telephony.ims.aidl.IImsConfig;
 import android.telephony.ims.aidl.IImsMmTelFeature;
@@ -48,6 +49,7 @@
 import java.util.Iterator;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 
 /**
  * Manages the Binding lifecycle of one ImsService as well as the relevant ImsFeatures that the
@@ -204,7 +206,7 @@
     private boolean mIsBound = false;
     private boolean mIsBinding = false;
     // Set of a pair of slotId->feature
-    private HashSet<ImsFeatureConfiguration.FeatureSlotPair> mImsFeatures;
+    private Set<ImsFeatureConfiguration.FeatureSlotPair> mImsFeatures;
     // Binder interfaces to the features set in mImsFeatures;
     private HashSet<ImsFeatureContainer> mImsFeatureBinders = new HashSet<>();
     private IImsServiceController mIImsServiceController;
@@ -361,10 +363,11 @@
      * @return {@link true} if the service is in the process of being bound, {@link false} if it
      * has failed.
      */
-    public boolean bind(HashSet<ImsFeatureConfiguration.FeatureSlotPair> imsFeatureSet) {
+    public boolean bind(Set<ImsFeatureConfiguration.FeatureSlotPair> imsFeatureSet) {
         synchronized (mLock) {
             if (!mIsBound && !mIsBinding) {
                 mIsBinding = true;
+                sanitizeFeatureConfig(imsFeatureSet);
                 mImsFeatures = imsFeatureSet;
                 grantPermissionsToService();
                 Intent imsServiceIntent = new Intent(getServiceInterface()).setComponent(
@@ -375,7 +378,7 @@
                 mLocalLog.log("binding " + imsFeatureSet);
                 Log.i(LOG_TAG, "Binding ImsService:" + mComponentName);
                 try {
-                    boolean bindSucceeded = startBindToService(imsServiceIntent,
+                    boolean bindSucceeded = mContext.bindService(imsServiceIntent,
                             mImsServiceConnection, serviceFlags);
                     if (!bindSucceeded) {
                         mLocalLog.log("    binding failed, retrying in "
@@ -400,12 +403,18 @@
     }
 
     /**
-     * Starts the bind to the ImsService. Overridden by subclasses that need to access the service
-     * in a different fashion.
+     * Ensure the feature includes MMTEL when it supports EMERGENCY_MMTEL, if not, remove.
      */
-    protected boolean startBindToService(Intent intent, ImsServiceConnection connection,
-            int flags) {
-        return mContext.bindService(intent, connection, flags);
+    private void sanitizeFeatureConfig(Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
+        Set<ImsFeatureConfiguration.FeatureSlotPair> emergencyMmtelFeatures = features.stream()
+                .filter(feature -> feature.featureType == ImsFeature.FEATURE_EMERGENCY_MMTEL)
+                .collect(Collectors.toSet());
+        for (ImsFeatureConfiguration.FeatureSlotPair feature : emergencyMmtelFeatures) {
+            if (!features.contains(new ImsFeatureConfiguration.FeatureSlotPair(feature.slotId,
+                    ImsFeature.FEATURE_MMTEL))) {
+                features.remove(feature);
+            }
+        }
     }
 
     /**
@@ -435,8 +444,9 @@
      * ImsFeature that is removed, {@link IImsServiceController#removeImsFeature} is called.
      */
     public void changeImsServiceFeatures(
-            HashSet<ImsFeatureConfiguration.FeatureSlotPair> newImsFeatures)
+            Set<ImsFeatureConfiguration.FeatureSlotPair> newImsFeatures)
             throws RemoteException {
+        sanitizeFeatureConfig(newImsFeatures);
         synchronized (mLock) {
             if (mImsFeatures.equals(newImsFeatures)) {
                 return;
@@ -639,7 +649,7 @@
         try {
             if (mPackageManager != null) {
                 mPackageManager.grantDefaultPermissionsToEnabledImsServices(pkgToGrant,
-                        mContext.getUserId());
+                        UserHandle.myUserId());
             }
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "Unable to grant permissions, binder died.");
@@ -705,12 +715,12 @@
             IInterface f = createImsFeature(featurePair.slotId, featurePair.featureType,
                     c.getCallback());
             addImsFeatureBinder(featurePair.slotId, featurePair.featureType, f);
-            // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
-            mCallbacks.imsServiceFeatureCreated(featurePair.slotId, featurePair.featureType, this);
         } else {
             // Don't update ImsService for emergency MMTEL feature.
             Log.i(LOG_TAG, "supports emergency calling on slot " + featurePair.slotId);
         }
+        // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
+        mCallbacks.imsServiceFeatureCreated(featurePair.slotId, featurePair.featureType, this);
         // Send callback to ImsServiceProxy to change supported ImsFeatures including emergency
         // MMTEL state.
         sendImsFeatureCreatedCallback(featurePair.slotId, featurePair.featureType);
@@ -722,6 +732,8 @@
             Log.w(LOG_TAG, "removeImsServiceFeature called with null values.");
             return;
         }
+        // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
+        mCallbacks.imsServiceFeatureRemoved(featurePair.slotId, featurePair.featureType, this);
         if (featurePair.featureType != ImsFeature.FEATURE_EMERGENCY_MMTEL) {
             ImsFeatureStatusCallback callbackToRemove = mFeatureStatusCallbacks.stream().filter(c ->
                     c.mSlotId == featurePair.slotId && c.mFeatureType == featurePair.featureType)
@@ -731,8 +743,6 @@
                 mFeatureStatusCallbacks.remove(callbackToRemove);
             }
             removeImsFeatureBinder(featurePair.slotId, featurePair.featureType);
-            // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
-            mCallbacks.imsServiceFeatureRemoved(featurePair.slotId, featurePair.featureType, this);
             try {
                 removeImsFeature(featurePair.slotId, featurePair.featureType,
                         (callbackToRemove != null ? callbackToRemove.getCallback() : null));
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java b/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java
index 11cae27..835d780 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java
@@ -171,7 +171,7 @@
         return mServiceController != null;
     }
 
-    protected MmTelInterfaceAdapter getInterface(int slotId, IImsFeatureStatusCallback c)
+    private MmTelInterfaceAdapter getInterface(int slotId, IImsFeatureStatusCallback c)
             throws RemoteException {
         IImsMMTelFeature feature = mServiceController.createMMTelFeature(slotId, c);
         if (feature == null) {
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceControllerStaticCompat.java b/src/java/com/android/internal/telephony/ims/ImsServiceControllerStaticCompat.java
deleted file mode 100644
index bd033db..0000000
--- a/src/java/com/android/internal/telephony/ims/ImsServiceControllerStaticCompat.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2018 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.ims;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-import com.android.ims.internal.IImsFeatureStatusCallback;
-import com.android.ims.internal.IImsService;
-
-/**
- * A compat layer for communicating with older devices that still used the ServiceManager to get
- * the ImsService.
- */
-
-public class ImsServiceControllerStaticCompat extends ImsServiceControllerCompat {
-
-    private static final String TAG = "ImsSCStaticCompat";
-
-    private static final String IMS_SERVICE_NAME = "ims";
-
-    private class ImsDeathRecipient implements IBinder.DeathRecipient {
-
-        private ComponentName mComponentName;
-        private ServiceConnection mServiceConnection;
-
-        ImsDeathRecipient(ComponentName name, ServiceConnection conn) {
-            mComponentName = name;
-            mServiceConnection = conn;
-        }
-
-        @Override
-        public void binderDied() {
-            Log.e(TAG, "ImsService(" + mComponentName + ") died. Restarting...");
-            // This is hacky... ImsServiceController uses the traditional service binding procedure,
-            // so we have to emulate it when using a persistent service.
-            mServiceConnection.onBindingDied(mComponentName);
-        }
-    }
-
-    private IImsService mImsServiceCompat = null;
-    private ImsDeathRecipient mImsDeathRecipient = null;
-
-    public ImsServiceControllerStaticCompat(Context context, ComponentName componentName,
-            ImsServiceController.ImsServiceControllerCallbacks callbacks) {
-        super(context, componentName, callbacks);
-    }
-
-    @Override
-    public boolean startBindToService(Intent intent, ImsServiceConnection connection, int flags) {
-        IBinder binder = ServiceManager.checkService(IMS_SERVICE_NAME);
-
-        if (binder == null) {
-            return false;
-        }
-        // This is a little hacky, but we are going to call the onServiceConnected to "pretend" like
-        // bindService has completed here, which will pass the binder to setServiceController and
-        // set up all supporting structures.
-        ComponentName name = new ComponentName(mContext, ImsServiceControllerStaticCompat.class);
-        connection.onServiceConnected(name, binder);
-        try {
-            mImsDeathRecipient = new ImsDeathRecipient(name, connection);
-            binder.linkToDeath(mImsDeathRecipient, 0);
-        } catch (RemoteException e) {
-            // The binder connection is already dead.. signal to the ImsServiceController to retry.
-            mImsDeathRecipient.binderDied();
-            mImsDeathRecipient = null;
-        }
-        return true;
-    }
-
-    @Override
-    protected void setServiceController(IBinder serviceController) {
-        if (serviceController == null) {
-            // The service controller has been set to null, meaning it has been unbound or died.
-            // Unlink if needed.
-            if (mImsServiceCompat != null) {
-                mImsServiceCompat.asBinder().unlinkToDeath(mImsDeathRecipient, 0);
-            }
-            mImsDeathRecipient = null;
-        }
-        mImsServiceCompat = IImsService.Stub.asInterface(serviceController);
-    }
-
-    @Override
-    // used for add/remove features and cleanup in ImsServiceController.
-    protected boolean isServiceControllerAvailable() {
-        return mImsServiceCompat != null;
-    }
-
-    @Override
-    protected MmTelInterfaceAdapter getInterface(int slotId, IImsFeatureStatusCallback c) {
-        if (mImsServiceCompat == null) {
-            Log.w(TAG, "getInterface: IImsService returned null.");
-            return null;
-        }
-        return new ImsServiceInterfaceAdapter(slotId, mImsServiceCompat.asBinder());
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceFeatureQueryManager.java b/src/java/com/android/internal/telephony/ims/ImsServiceFeatureQueryManager.java
index 5280ff3..638b76f 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceFeatureQueryManager.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceFeatureQueryManager.java
@@ -83,6 +83,21 @@
             Log.w(LOG_TAG, "onServiceDisconnected for component: " + name);
         }
 
+        @Override
+        public void onBindingDied(ComponentName name) {
+            Log.w(LOG_TAG, "onBindingDied: " + name);
+            cleanup();
+            // retry again!
+            mListener.onError(name);
+        }
+
+        @Override
+        public void onNullBinding(ComponentName name) {
+            Log.w(LOG_TAG, "onNullBinding: " + name);
+            cleanup();
+            mListener.onPermanentError(name);
+        }
+
         private void queryImsFeatures(IImsServiceController controller) {
             ImsFeatureConfiguration config;
             try {
@@ -90,6 +105,7 @@
             } catch (Exception e) {
                 Log.w(LOG_TAG, "queryImsFeatures - error: " + e);
                 cleanup();
+                // Retry again!
                 mListener.onError(mName);
                 return;
             }
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceInterfaceAdapter.java b/src/java/com/android/internal/telephony/ims/ImsServiceInterfaceAdapter.java
deleted file mode 100644
index f554e6f..0000000
--- a/src/java/com/android/internal/telephony/ims/ImsServiceInterfaceAdapter.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2018 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.ims;
-
-import android.app.PendingIntent;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.ims.ImsCallProfile;
-import android.telephony.ims.compat.feature.ImsFeature;
-
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsService;
-import com.android.ims.internal.IImsUt;
-
-/**
- * Compatibility layer for IImsService implementations of IMS. Converts "generic" MMTel commands
- * to implementation.
- */
-
-public class ImsServiceInterfaceAdapter extends MmTelInterfaceAdapter {
-
-    private static final int SERVICE_ID = ImsFeature.MMTEL;
-
-    public ImsServiceInterfaceAdapter(int slotId, IBinder binder) {
-        super(slotId, binder);
-    }
-
-    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
-            throws RemoteException {
-        return getInterface().open(mSlotId, ImsFeature.MMTEL, incomingCallIntent, listener);
-    }
-
-    public void endSession(int sessionId) throws RemoteException {
-        getInterface().close(sessionId);
-    }
-
-    public boolean isConnected(int callSessionType, int callType) throws RemoteException {
-        return getInterface().isConnected(SERVICE_ID, callSessionType, callType);
-    }
-
-    public boolean isOpened() throws RemoteException {
-        return getInterface().isOpened(SERVICE_ID);
-    }
-
-    public int getFeatureState() throws RemoteException {
-        return ImsFeature.STATE_READY;
-    }
-
-    public void addRegistrationListener(IImsRegistrationListener listener) throws RemoteException {
-        getInterface().addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
-    }
-
-    public void removeRegistrationListener(IImsRegistrationListener listener)
-            throws RemoteException {
-        // Not Implemented in the old ImsService. If the registration listener becomes invalid, the
-        // ImsService will remove it.
-    }
-
-    public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType)
-            throws RemoteException {
-        return getInterface().createCallProfile(sessionId, callSessionType, callType);
-    }
-
-    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile)
-            throws RemoteException {
-        return getInterface().createCallSession(sessionId, profile, null);
-    }
-
-    public IImsCallSession getPendingCallSession(int sessionId, String callId)
-            throws RemoteException {
-        return getInterface().getPendingCallSession(sessionId, callId);
-    }
-
-    public IImsUt getUtInterface() throws RemoteException {
-        return getInterface().getUtInterface(SERVICE_ID);
-    }
-
-    public IImsConfig getConfigInterface() throws RemoteException {
-        return getInterface().getConfigInterface(mSlotId);
-    }
-
-    public void turnOnIms() throws RemoteException {
-        getInterface().turnOnIms(mSlotId);
-    }
-
-    public void turnOffIms() throws RemoteException {
-        getInterface().turnOffIms(mSlotId);
-    }
-
-    public IImsEcbm getEcbmInterface() throws RemoteException {
-        return getInterface().getEcbmInterface(SERVICE_ID);
-    }
-
-    public void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException {
-        getInterface().setUiTTYMode(SERVICE_ID, uiTtyMode, onComplete);
-    }
-
-    public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
-        return getInterface().getMultiEndpointInterface(SERVICE_ID);
-    }
-
-    private IImsService getInterface() throws RemoteException {
-        IImsService feature = IImsService.Stub.asInterface(mBinder);
-        if (feature == null) {
-            throw new RemoteException("Binder not Available");
-        }
-        return feature;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/RcsEventQueryHelper.java b/src/java/com/android/internal/telephony/ims/RcsEventQueryHelper.java
deleted file mode 100644
index 062638c..0000000
--- a/src/java/com/android/internal/telephony/ims/RcsEventQueryHelper.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.ICON_CHANGED_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.NAME_CHANGED_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_JOINED_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_LEFT_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.RCS_GROUP_THREAD_URI;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_URI;
-import static android.provider.Telephony.RcsColumns.RcsParticipantEventColumns.ALIAS_CHANGE_EVENT_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsParticipantEventColumns.NEW_ALIAS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.DESTINATION_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.EVENT_TYPE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.ICON_CHANGED_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.NAME_CHANGED_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.NEW_ICON_URI_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.NEW_NAME_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.PARTICIPANT_JOINED_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.PARTICIPANT_LEFT_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.SOURCE_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.TIMESTAMP_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedEventHelper.RCS_EVENT_QUERY_URI;
-import static android.telephony.ims.RcsQueryContinuationToken.QUERY_CONTINUATION_TOKEN;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.telephony.Rlog;
-import android.telephony.ims.RcsEventDescriptor;
-import android.telephony.ims.RcsEventQueryResultDescriptor;
-import android.telephony.ims.RcsGroupThreadIconChangedEventDescriptor;
-import android.telephony.ims.RcsGroupThreadNameChangedEventDescriptor;
-import android.telephony.ims.RcsGroupThreadParticipantJoinedEventDescriptor;
-import android.telephony.ims.RcsGroupThreadParticipantLeftEventDescriptor;
-import android.telephony.ims.RcsParticipantAliasChangedEventDescriptor;
-import android.telephony.ims.RcsQueryContinuationToken;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class RcsEventQueryHelper {
-    private final ContentResolver mContentResolver;
-
-    RcsEventQueryHelper(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-    }
-
-    Uri getParticipantEventInsertionUri(int participantId) {
-        return RCS_PARTICIPANT_URI.buildUpon().appendPath(Integer.toString(participantId))
-                .appendPath(ALIAS_CHANGE_EVENT_URI_PART).build();
-    }
-
-    RcsEventQueryResultDescriptor performEventQuery(Bundle bundle) throws RemoteException {
-        RcsQueryContinuationToken continuationToken = null;
-        List<RcsEventDescriptor> eventList = new ArrayList<>();
-
-        try (Cursor cursor = mContentResolver.query(RCS_EVENT_QUERY_URI, null, bundle, null)) {
-            if (cursor == null) {
-                throw new RemoteException("Event query failed, bundle: " + bundle);
-            }
-
-            while (cursor.moveToNext()) {
-                int eventType = cursor.getInt(cursor.getColumnIndex(EVENT_TYPE_COLUMN));
-                switch (eventType) {
-                    case PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE:
-                        eventList.add(createNewParticipantAliasChangedEvent(cursor));
-                        break;
-                    case PARTICIPANT_JOINED_EVENT_TYPE:
-                        eventList.add(createNewParticipantJoinedEvent(cursor));
-                        break;
-                    case PARTICIPANT_LEFT_EVENT_TYPE:
-                        eventList.add(createNewParticipantLeftEvent(cursor));
-                        break;
-                    case NAME_CHANGED_EVENT_TYPE:
-                        eventList.add(createNewGroupNameChangedEvent(cursor));
-                        break;
-                    case ICON_CHANGED_EVENT_TYPE:
-                        eventList.add(createNewGroupIconChangedEvent(cursor));
-                        break;
-                    default:
-                        Rlog.e(RcsMessageController.TAG,
-                                "RcsEventQueryHelper: invalid event type: " + eventType);
-                }
-            }
-
-            Bundle cursorExtras = cursor.getExtras();
-            if (cursorExtras != null) {
-                continuationToken = cursorExtras.getParcelable(QUERY_CONTINUATION_TOKEN);
-            }
-        }
-
-        return new RcsEventQueryResultDescriptor(continuationToken, eventList);
-    }
-
-    int createGroupThreadEvent(int eventType, long timestamp, int threadId,
-            int originationParticipantId, ContentValues eventSpecificValues)
-            throws RemoteException {
-        ContentValues values = new ContentValues(eventSpecificValues);
-        values.put(EVENT_TYPE_COLUMN, eventType);
-        values.put(TIMESTAMP_COLUMN, timestamp);
-        values.put(SOURCE_PARTICIPANT_ID_COLUMN, originationParticipantId);
-
-        Uri eventUri = RCS_GROUP_THREAD_URI.buildUpon().appendPath(
-                Integer.toString(threadId)).appendPath(getPathForEventType(eventType)).build();
-        Uri insertionUri = mContentResolver.insert(eventUri, values);
-
-        int eventId = 0;
-        if (insertionUri != null) {
-            eventId = Integer.parseInt(insertionUri.getLastPathSegment());
-        }
-
-        if (eventId <= 0) {
-            throw new RemoteException(
-                "Could not create event with type: " + eventType + " on thread: " + threadId);
-        }
-        return eventId;
-    }
-
-    private String getPathForEventType(int eventType) throws RemoteException {
-        switch (eventType) {
-            case PARTICIPANT_JOINED_EVENT_TYPE:
-                return PARTICIPANT_JOINED_URI_PART;
-            case PARTICIPANT_LEFT_EVENT_TYPE:
-                return PARTICIPANT_LEFT_URI_PART;
-            case NAME_CHANGED_EVENT_TYPE:
-                return NAME_CHANGED_URI_PART;
-            case ICON_CHANGED_EVENT_TYPE:
-                return ICON_CHANGED_URI_PART;
-            default:
-                throw new RemoteException("Event type unrecognized: " + eventType);
-        }
-    }
-
-    private RcsGroupThreadIconChangedEventDescriptor createNewGroupIconChangedEvent(Cursor cursor) {
-        String newIcon = cursor.getString(cursor.getColumnIndex(NEW_ICON_URI_COLUMN));
-
-        return new RcsGroupThreadIconChangedEventDescriptor(
-                cursor.getLong(cursor.getColumnIndex(TIMESTAMP_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(SOURCE_PARTICIPANT_ID_COLUMN)),
-                newIcon == null ? null : Uri.parse(newIcon));
-    }
-
-    private RcsGroupThreadNameChangedEventDescriptor createNewGroupNameChangedEvent(Cursor cursor) {
-        return new RcsGroupThreadNameChangedEventDescriptor(
-                cursor.getLong(cursor.getColumnIndex(TIMESTAMP_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(SOURCE_PARTICIPANT_ID_COLUMN)),
-                cursor.getString(cursor.getColumnIndex(NEW_NAME_COLUMN)));
-    }
-
-    private RcsGroupThreadParticipantLeftEventDescriptor
-            createNewParticipantLeftEvent(Cursor cursor) {
-        return new RcsGroupThreadParticipantLeftEventDescriptor(
-                cursor.getLong(cursor.getColumnIndex(TIMESTAMP_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(SOURCE_PARTICIPANT_ID_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(DESTINATION_PARTICIPANT_ID_COLUMN)));
-    }
-
-    private RcsGroupThreadParticipantJoinedEventDescriptor
-            createNewParticipantJoinedEvent(Cursor cursor) {
-        return new RcsGroupThreadParticipantJoinedEventDescriptor(
-                cursor.getLong(cursor.getColumnIndex(TIMESTAMP_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(SOURCE_PARTICIPANT_ID_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(DESTINATION_PARTICIPANT_ID_COLUMN)));
-    }
-
-    private RcsParticipantAliasChangedEventDescriptor
-            createNewParticipantAliasChangedEvent(Cursor cursor) {
-        return new RcsParticipantAliasChangedEventDescriptor(
-                cursor.getLong(cursor.getColumnIndex(TIMESTAMP_COLUMN)),
-                cursor.getInt(cursor.getColumnIndex(SOURCE_PARTICIPANT_ID_COLUMN)),
-                cursor.getString(cursor.getColumnIndex(NEW_ALIAS_COLUMN)));
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/RcsMessageController.java b/src/java/com/android/internal/telephony/ims/RcsMessageController.java
deleted file mode 100644
index 3f9714d..0000000
--- a/src/java/com/android/internal/telephony/ims/RcsMessageController.java
+++ /dev/null
@@ -1,1043 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import static android.provider.Telephony.RcsColumns.Rcs1To1ThreadColumns.FALLBACK_THREAD_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.Rcs1To1ThreadColumns.RCS_1_TO_1_THREAD_URI;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.ICON_CHANGED_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.NAME_CHANGED_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_JOINED_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_LEFT_EVENT_TYPE;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.CONTENT_TYPE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.CONTENT_URI_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.DURATION_MILLIS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_SIZE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_TRANSFER_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_TRANSFER_URI;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.HEIGHT_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.PREVIEW_TYPE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.PREVIEW_URI_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.SESSION_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.SUCCESSFULLY_TRANSFERRED_BYTES;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.TRANSFER_STATUS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.WIDTH_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.CONFERENCE_URI_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_ICON_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_NAME_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.OWNER_PARTICIPANT_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.RCS_GROUP_THREAD_URI;
-import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.ARRIVAL_TIMESTAMP_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.INCOMING_MESSAGE_URI;
-import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.SEEN_TIMESTAMP_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.SENDER_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.GLOBAL_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.LATITUDE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.LONGITUDE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.MESSAGE_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.MESSAGE_TEXT_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.ORIGINATION_TIMESTAMP_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.STATUS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.SUB_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageDeliveryColumns.DELIVERED_TIMESTAMP_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.CANONICAL_ADDRESS_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_ALIAS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_URI;
-import static android.provider.Telephony.RcsColumns.RcsParticipantEventColumns.NEW_ALIAS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.DESTINATION_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.NEW_ICON_URI_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.NEW_NAME_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.SOURCE_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadEventColumns.TIMESTAMP_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_GROUP;
-import static android.provider.Telephony.RcsColumns.TRANSACTION_FAILED;
-import static android.telephony.ims.RcsEventQueryParams.EVENT_QUERY_PARAMETERS_KEY;
-import static android.telephony.ims.RcsMessageQueryParams.MESSAGE_QUERY_PARAMETERS_KEY;
-import static android.telephony.ims.RcsParticipantQueryParams.PARTICIPANT_QUERY_PARAMETERS_KEY;
-import static android.telephony.ims.RcsQueryContinuationToken.QUERY_CONTINUATION_TOKEN;
-import static android.telephony.ims.RcsThreadQueryParams.THREAD_QUERY_PARAMETERS_KEY;
-
-import static com.android.internal.telephony.ims.RcsMessageStoreUtil.getMessageTableUri;
-import static com.android.internal.telephony.ims.RcsParticipantQueryHelper.getUriForParticipant;
-import static com.android.internal.telephony.ims.RcsThreadHelper.get1To1ThreadUri;
-import static com.android.internal.telephony.ims.RcsThreadHelper.getGroupThreadUri;
-import static com.android.internal.telephony.ims.RcsThreadHelper.getParticipantInThreadUri;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Telephony;
-import android.telephony.Rlog;
-import android.telephony.ims.RcsEventQueryParams;
-import android.telephony.ims.RcsEventQueryResultDescriptor;
-import android.telephony.ims.RcsFileTransferCreationParams;
-import android.telephony.ims.RcsIncomingMessageCreationParams;
-import android.telephony.ims.RcsMessageManager;
-import android.telephony.ims.RcsMessageQueryParams;
-import android.telephony.ims.RcsMessageQueryResultParcelable;
-import android.telephony.ims.RcsMessageSnippet;
-import android.telephony.ims.RcsOutgoingMessageCreationParams;
-import android.telephony.ims.RcsParticipantQueryParams;
-import android.telephony.ims.RcsParticipantQueryResultParcelable;
-import android.telephony.ims.RcsQueryContinuationToken;
-import android.telephony.ims.RcsThreadQueryParams;
-import android.telephony.ims.RcsThreadQueryResultParcelable;
-import android.telephony.ims.aidl.IRcsMessage;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
-import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
-
-/**
- * Backing implementation of {@link RcsMessageManager}.
- */
-public class RcsMessageController extends IRcsMessage.Stub {
-
-    static final String TAG = "RcsMsgController";
-    private static final String RCS_SERVICE_NAME = Context.TELEPHONY_RCS_MESSAGE_SERVICE;
-
-    private static RcsMessageController sInstance;
-
-    private final Context mContext;
-    private final ContentResolver mContentResolver;
-    private final RcsParticipantQueryHelper mParticipantQueryHelper;
-    private final RcsMessageQueryHelper mMessageQueryHelper;
-    private final RcsEventQueryHelper mEventQueryHelper;
-    private final RcsThreadHelper mThreadHelper;
-    private final RcsMessageStoreUtil mMessageStoreUtil;
-
-    /**
-     * Initialize the instance. Should only be called once.
-     */
-    public static RcsMessageController init(Context context) {
-        synchronized (RcsMessageController.class) {
-            if (sInstance == null) {
-                sInstance = new RcsMessageController(context);
-                if (ServiceManager.getService(RCS_SERVICE_NAME) == null) {
-                    ServiceManager.addService(RCS_SERVICE_NAME, sInstance);
-                }
-            } else {
-                Rlog.e(TAG, "init() called multiple times! sInstance = " + sInstance);
-            }
-        }
-        return sInstance;
-    }
-
-    /**
-     * This call cannot be nested with either {@link #performWriteOperation} or {@link
-     * #performReadOperation} as the permission check will then fail since we have cleared the
-     * calling identity.
-     */
-    private void performWriteOperation(String callingPackage, ThrowingRunnable fn) {
-        performWriteOperation(callingPackage, () -> {
-            fn.run();
-            return null;
-        });
-    }
-
-    /**
-     * This call cannot be nested with either {@link #performWriteOperation} or {@link
-     * #performReadOperation} as the permission check will then fail since we have cleared the
-     * calling identity.
-     */
-    private <T> T performWriteOperation(String callingPackage, ThrowingSupplier<T> fn) {
-        RcsPermissions.checkWritePermissions(mContext, callingPackage);
-        return Binder.withCleanCallingIdentity(fn);
-    }
-
-    /**
-     * This call cannot be nested with either {@link #performWriteOperation} or {@link
-     * #performReadOperation} as the permission check will then fail since we have cleared the
-     * calling identity.
-     */
-    private <T> T performReadOperation(String callingPackage, ThrowingSupplier<T> fn) {
-        RcsPermissions.checkReadPermissions(mContext, callingPackage);
-        return Binder.withCleanCallingIdentity(fn);
-    }
-
-    @VisibleForTesting
-    public RcsMessageController(Context context) {
-        mContext = context;
-        mContentResolver = context.getContentResolver();
-        mParticipantQueryHelper = new RcsParticipantQueryHelper(mContentResolver);
-        mMessageQueryHelper = new RcsMessageQueryHelper(mContentResolver);
-        mThreadHelper = new RcsThreadHelper(mContentResolver, mParticipantQueryHelper);
-        mEventQueryHelper = new RcsEventQueryHelper(mContentResolver);
-        mMessageStoreUtil = new RcsMessageStoreUtil(mContentResolver);
-    }
-
-    @Override
-    public boolean deleteThread(int threadId, int threadType, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            int deletionCount = mContentResolver.delete(
-                    threadType == THREAD_TYPE_GROUP ? RCS_GROUP_THREAD_URI : RCS_1_TO_1_THREAD_URI,
-                    RCS_THREAD_ID_COLUMN + "=?",
-                    new String[]{Integer.toString(threadId)});
-
-            return deletionCount > 0;
-        });
-    }
-
-    @Override
-    public RcsMessageSnippet getMessageSnippet(int threadId, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            // TODO - implement
-            return null;
-        });
-    }
-
-    @Override
-    public RcsThreadQueryResultParcelable getRcsThreads(RcsThreadQueryParams queryParameters,
-            String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(THREAD_QUERY_PARAMETERS_KEY, queryParameters);
-            return mThreadHelper.performThreadQuery(bundle);
-        });
-    }
-
-    @Override
-    public RcsThreadQueryResultParcelable getRcsThreadsWithToken(
-            RcsQueryContinuationToken continuationToken, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(QUERY_CONTINUATION_TOKEN, continuationToken);
-            return mThreadHelper.performThreadQuery(bundle);
-        });
-    }
-
-    @Override
-    public RcsParticipantQueryResultParcelable getParticipants(
-            RcsParticipantQueryParams queryParameters, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(PARTICIPANT_QUERY_PARAMETERS_KEY, queryParameters);
-            return mParticipantQueryHelper.performParticipantQuery(bundle);
-        });
-    }
-
-    @Override
-    public RcsParticipantQueryResultParcelable getParticipantsWithToken(
-            RcsQueryContinuationToken continuationToken, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(QUERY_CONTINUATION_TOKEN, continuationToken);
-            return mParticipantQueryHelper.performParticipantQuery(bundle);
-        });
-    }
-
-    @Override
-    public RcsMessageQueryResultParcelable getMessages(RcsMessageQueryParams queryParams,
-            String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(MESSAGE_QUERY_PARAMETERS_KEY, queryParams);
-            return mMessageQueryHelper.performMessageQuery(bundle);
-        });
-    }
-
-    @Override
-    public RcsMessageQueryResultParcelable getMessagesWithToken(
-            RcsQueryContinuationToken continuationToken, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(QUERY_CONTINUATION_TOKEN, continuationToken);
-            return mMessageQueryHelper.performMessageQuery(bundle);
-        });
-    }
-
-    @Override
-    public RcsEventQueryResultDescriptor getEvents(RcsEventQueryParams queryParameters,
-            String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(EVENT_QUERY_PARAMETERS_KEY, queryParameters);
-            return mEventQueryHelper.performEventQuery(bundle);
-        });
-    }
-
-    @Override
-    public RcsEventQueryResultDescriptor getEventsWithToken(
-            RcsQueryContinuationToken continuationToken, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(QUERY_CONTINUATION_TOKEN, continuationToken);
-            return mEventQueryHelper.performEventQuery(bundle);
-        });
-    }
-
-    @Override
-    public int createRcs1To1Thread(int recipientId, String callingPackage) {
-        return performWriteOperation(callingPackage,
-                () -> mThreadHelper.create1To1Thread(recipientId));
-    }
-
-    @Override
-    public int createGroupThread(int[] participantIds, String groupName, Uri groupIcon,
-            String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            int groupThreadId = mThreadHelper.createGroupThread(groupName, groupIcon);
-            if (groupThreadId <= 0) {
-                throw new RemoteException("Could not create RcsGroupThread.");
-            }
-
-            // Insert participants
-            // TODO(123718879): Instead of adding participants here, add them under RcsProvider
-            //  under one transaction
-            if (participantIds != null) {
-                for (int participantId : participantIds) {
-                    mThreadHelper.addParticipantToGroupThread(groupThreadId, participantId);
-                }
-            }
-
-            return groupThreadId;
-        });
-    }
-
-    /**
-     * TODO(109759350) Instead of sending the update query directly to RcsProvider, this function
-     * orchestrates between RcsProvider and MmsSmsProvider. This is because we are not fully decided
-     * on whether we should have RCS storage in a separate database file.
-     */
-    @Override
-    public int createRcsParticipant(String canonicalAddress, String alias, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues contentValues = new ContentValues();
-
-            long canonicalAddressId = Telephony.RcsColumns.RcsCanonicalAddressHelper
-                    .getOrCreateCanonicalAddressId(mContentResolver, canonicalAddress);
-
-            if (canonicalAddressId == TRANSACTION_FAILED) {
-                throw new RemoteException("Could not create or make canonical address entry");
-            }
-
-            contentValues.put(CANONICAL_ADDRESS_ID_COLUMN, canonicalAddressId);
-            contentValues.put(RCS_ALIAS_COLUMN, alias);
-
-            // TODO (123719857) - Disallow creation of duplicate participants
-            Uri newParticipantUri = mContentResolver.insert(RCS_PARTICIPANT_URI, contentValues);
-            int newParticipantRowId;
-
-            if (newParticipantUri == null) {
-                throw new RemoteException("Error inserting new participant into RcsProvider");
-            }
-
-            try {
-                newParticipantRowId = Integer.parseInt(newParticipantUri.getLastPathSegment());
-            } catch (NumberFormatException e) {
-                throw new RemoteException(
-                        "Uri returned after creating a participant is malformed: "
-                                + newParticipantUri);
-            }
-
-            return newParticipantRowId;
-        });
-    }
-
-    @Override
-    public String getRcsParticipantCanonicalAddress(int participantId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(RCS_PARTICIPANT_URI,
-                        Telephony.CanonicalAddressesColumns.ADDRESS, RCS_PARTICIPANT_ID_COLUMN,
-                        participantId));
-    }
-
-    @Override
-    public String getRcsParticipantAlias(int participantId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(RCS_PARTICIPANT_URI,
-                        RCS_ALIAS_COLUMN,
-                        RCS_PARTICIPANT_ID_COLUMN, participantId));
-    }
-
-    @Override
-    public void setRcsParticipantAlias(int id, String alias, String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mMessageStoreUtil.updateValueOfProviderUri(getUriForParticipant(id),
-                        RCS_ALIAS_COLUMN,
-                        alias, "Could not update RCS participant alias"));
-    }
-
-    @Override
-    public String getRcsParticipantContactId(int participantId, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            // TODO - implement
-            return null;
-        });
-    }
-
-    @Override
-    public void setRcsParticipantContactId(int participantId, String contactId,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> {
-            // TODO - implement
-        });
-    }
-
-    @Override
-    public void set1To1ThreadFallbackThreadId(int rcsThreadId, long fallbackId,
-            String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mMessageStoreUtil.updateValueOfProviderUri(get1To1ThreadUri(rcsThreadId),
-                        FALLBACK_THREAD_ID_COLUMN, fallbackId, "Could not set fallback thread ID"));
-    }
-
-    @Override
-    public long get1To1ThreadFallbackThreadId(int rcsThreadId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getLongValueFromTableRow(RCS_1_TO_1_THREAD_URI,
-                        FALLBACK_THREAD_ID_COLUMN,
-                        RCS_THREAD_ID_COLUMN, rcsThreadId));
-    }
-
-    @Override
-    public int get1To1ThreadOtherParticipantId(int rcsThreadId, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            Uri uri = get1To1ThreadUri(rcsThreadId);
-            String[] projection = new String[]{RCS_PARTICIPANT_ID_COLUMN};
-            try (Cursor cursor = mContentResolver.query(uri, projection, null, null)) {
-                if (cursor == null || cursor.getCount() != 1) {
-                    throw new RemoteException("Could not get the thread recipient");
-                }
-                cursor.moveToNext();
-                return cursor.getInt(
-                        cursor.getColumnIndex(RCS_PARTICIPANT_ID_COLUMN));
-            }
-        });
-    }
-
-    @Override
-    public void setGroupThreadName(int rcsThreadId, String groupName, String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mMessageStoreUtil.updateValueOfProviderUri(getGroupThreadUri(rcsThreadId),
-                        GROUP_NAME_COLUMN, groupName, "Could not update group name"));
-    }
-
-    @Override
-    public String getGroupThreadName(int rcsThreadId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(RCS_GROUP_THREAD_URI,
-                        GROUP_NAME_COLUMN,
-                        RCS_THREAD_ID_COLUMN, rcsThreadId));
-    }
-
-    @Override
-    public void setGroupThreadIcon(int rcsThreadId, Uri groupIcon, String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mMessageStoreUtil.updateValueOfProviderUri(getGroupThreadUri(rcsThreadId),
-                        GROUP_ICON_COLUMN, groupIcon, "Could not update group icon"));
-    }
-
-    @Override
-    public Uri getGroupThreadIcon(int rcsThreadId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getUriValueFromTableRow(RCS_GROUP_THREAD_URI,
-                        GROUP_ICON_COLUMN,
-                        RCS_THREAD_ID_COLUMN, rcsThreadId));
-    }
-
-    @Override
-    public void setGroupThreadOwner(int rcsThreadId, int participantId, String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mMessageStoreUtil.updateValueOfProviderUri(getGroupThreadUri(rcsThreadId),
-                        OWNER_PARTICIPANT_COLUMN, participantId, "Could not set the group owner"));
-    }
-
-    @Override
-    public int getGroupThreadOwner(int rcsThreadId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getIntValueFromTableRow(RCS_GROUP_THREAD_URI,
-                        OWNER_PARTICIPANT_COLUMN,
-                        RCS_THREAD_ID_COLUMN, rcsThreadId));
-    }
-
-    @Override
-    public void setGroupThreadConferenceUri(int rcsThreadId, Uri uri, String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mMessageStoreUtil.updateValueOfProviderUri(getGroupThreadUri(rcsThreadId),
-                        CONFERENCE_URI_COLUMN, uri, "Could not set the conference URI for group"));
-    }
-
-    @Override
-    public Uri getGroupThreadConferenceUri(int rcsThreadId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getUriValueFromTableRow(RCS_GROUP_THREAD_URI,
-                        CONFERENCE_URI_COLUMN, RCS_THREAD_ID_COLUMN, rcsThreadId));
-    }
-
-    @Override
-    public void addParticipantToGroupThread(int rcsThreadId, int participantId,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> {
-            mThreadHelper.addParticipantToGroupThread(rcsThreadId, participantId);
-        });
-    }
-
-    @Override
-    public void removeParticipantFromGroupThread(int rcsThreadId, int participantId,
-            String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mContentResolver.delete(getParticipantInThreadUri(rcsThreadId, participantId),
-                        null,
-                        null));
-    }
-
-    @Override
-    public int addIncomingMessage(int rcsThreadId,
-            RcsIncomingMessageCreationParams rcsIncomingMessageCreationParams,
-            String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues contentValues = new ContentValues();
-
-            contentValues.put(ARRIVAL_TIMESTAMP_COLUMN,
-                    rcsIncomingMessageCreationParams.getArrivalTimestamp());
-            contentValues.put(SEEN_TIMESTAMP_COLUMN,
-                    rcsIncomingMessageCreationParams.getSeenTimestamp());
-            contentValues.put(SENDER_PARTICIPANT_ID_COLUMN,
-                    rcsIncomingMessageCreationParams.getSenderParticipantId());
-
-            mMessageQueryHelper.createContentValuesForGenericMessage(contentValues, rcsThreadId,
-                    rcsIncomingMessageCreationParams);
-
-            return addMessage(rcsThreadId, true, contentValues);
-        });
-    }
-
-    @Override
-    public int addOutgoingMessage(int rcsThreadId,
-            RcsOutgoingMessageCreationParams rcsOutgoingMessageCreationParameters,
-            String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues contentValues = new ContentValues();
-
-            mMessageQueryHelper.createContentValuesForGenericMessage(contentValues, rcsThreadId,
-                    rcsOutgoingMessageCreationParameters);
-
-            return addMessage(rcsThreadId, false, contentValues);
-        });
-    }
-
-    private int addMessage(int rcsThreadId, boolean isIncoming, ContentValues contentValues)
-            throws RemoteException {
-        Uri uri = mContentResolver.insert(mMessageQueryHelper.getMessageInsertionUri(isIncoming),
-                contentValues);
-
-        if (uri == null) {
-            throw new RemoteException(
-                    "Could not create message on thread, threadId: " + rcsThreadId);
-        }
-
-        return Integer.parseInt(uri.getLastPathSegment());
-    }
-
-    @Override
-    public void deleteMessage(int messageId, boolean isIncoming, int rcsThreadId, boolean isGroup,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mContentResolver.delete(
-                mMessageQueryHelper.getMessageDeletionUri(messageId, isIncoming, rcsThreadId,
-                        isGroup),
-                null, null));
-    }
-
-    @Override
-    public void setMessageSubId(int messageId, boolean isIncoming, int subId,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming), SUB_ID_COLUMN,
-                subId, "Could not set subscription ID for message"));
-    }
-
-    @Override
-    public int getMessageSubId(int messageId, boolean isIncoming, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getIntValueFromTableRow(getMessageTableUri(isIncoming),
-                        SUB_ID_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void setMessageStatus(int messageId, boolean isIncoming, int status,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming), STATUS_COLUMN,
-                status, "Could not set the status for message"));
-    }
-
-    @Override
-    public int getMessageStatus(int messageId, boolean isIncoming, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getIntValueFromTableRow(getMessageTableUri(isIncoming),
-                        STATUS_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void setMessageOriginationTimestamp(int messageId, boolean isIncoming,
-            long originationTimestamp, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming),
-                ORIGINATION_TIMESTAMP_COLUMN, originationTimestamp,
-                "Could not set the origination timestamp for message"));
-    }
-
-    @Override
-    public long getMessageOriginationTimestamp(int messageId, boolean isIncoming,
-            String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getLongValueFromTableRow(getMessageTableUri(isIncoming),
-                        ORIGINATION_TIMESTAMP_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void setGlobalMessageIdForMessage(int messageId, boolean isIncoming, String globalId,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming),
-                GLOBAL_ID_COLUMN,
-                globalId, "Could not set the global ID for message"));
-    }
-
-    @Override
-    public String getGlobalMessageIdForMessage(int messageId, boolean isIncoming,
-            String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(getMessageTableUri(isIncoming),
-                        GLOBAL_ID_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void setMessageArrivalTimestamp(int messageId, boolean isIncoming,
-            long arrivalTimestamp, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming),
-                ARRIVAL_TIMESTAMP_COLUMN, arrivalTimestamp,
-                "Could not update the arrival timestamp for message"));
-    }
-
-    @Override
-    public long getMessageArrivalTimestamp(int messageId, boolean isIncoming,
-            String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getLongValueFromTableRow(getMessageTableUri(isIncoming),
-                        ARRIVAL_TIMESTAMP_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void setMessageSeenTimestamp(int messageId, boolean isIncoming,
-            long notifiedTimestamp, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming),
-                SEEN_TIMESTAMP_COLUMN, notifiedTimestamp,
-                "Could not set the notified timestamp for message"));
-    }
-
-    @Override
-    public long getMessageSeenTimestamp(int messageId, boolean isIncoming, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getLongValueFromTableRow(getMessageTableUri(isIncoming),
-                        SEEN_TIMESTAMP_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public int[] getMessageRecipients(int messageId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageQueryHelper.getDeliveryParticipantsForMessage(messageId));
-    }
-
-    @Override
-    public long getOutgoingDeliveryDeliveredTimestamp(int messageId, int participantId,
-            String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageQueryHelper.getLongValueFromDelivery(messageId, participantId,
-                        DELIVERED_TIMESTAMP_COLUMN));
-    }
-
-    @Override
-    public void setOutgoingDeliveryDeliveredTimestamp(int messageId, int participantId,
-            long deliveredTimestamp, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageDeliveryUri(messageId, participantId),
-                DELIVERED_TIMESTAMP_COLUMN, deliveredTimestamp,
-                "Could not update the delivered timestamp for outgoing delivery"));
-    }
-
-    @Override
-    public long getOutgoingDeliverySeenTimestamp(int messageId, int participantId,
-            String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageQueryHelper.getLongValueFromDelivery(messageId, participantId,
-                        SEEN_TIMESTAMP_COLUMN));
-    }
-
-    @Override
-    public void setOutgoingDeliverySeenTimestamp(int messageId, int participantId,
-            long seenTimestamp, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageDeliveryUri(messageId, participantId),
-                SEEN_TIMESTAMP_COLUMN, seenTimestamp,
-                "Could not update the seen timestamp for outgoing delivery"));
-    }
-
-    @Override
-    public int getOutgoingDeliveryStatus(int messageId, int participantId, String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            // TODO - implement
-            return 0;
-        });
-    }
-
-    @Override
-    public void setOutgoingDeliveryStatus(int messageId, int participantId, int status,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> {
-            // TODO - implement
-        });
-    }
-
-    @Override
-    public void setTextForMessage(int messageId, boolean isIncoming, String text,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming),
-                MESSAGE_TEXT_COLUMN,
-                text, "Could not set the text for message"));
-    }
-
-    @Override
-    public String getTextForMessage(int messageId, boolean isIncoming, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(getMessageTableUri(isIncoming),
-                        MESSAGE_TEXT_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void setLatitudeForMessage(int messageId, boolean isIncoming, double latitude,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming), LATITUDE_COLUMN,
-                latitude, "Could not update latitude for message"));
-    }
-
-    @Override
-    public double getLatitudeForMessage(int messageId, boolean isIncoming, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getDoubleValueFromTableRow(getMessageTableUri(isIncoming),
-                        LATITUDE_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void setLongitudeForMessage(int messageId, boolean isIncoming, double longitude,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getMessageUpdateUri(messageId, isIncoming),
-                LONGITUDE_COLUMN,
-                longitude, "Could not set longitude for message"));
-    }
-
-    @Override
-    public double getLongitudeForMessage(int messageId, boolean isIncoming, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getDoubleValueFromTableRow(getMessageTableUri(isIncoming),
-                        LONGITUDE_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public int[] getFileTransfersAttachedToMessage(int messageId, boolean isIncoming,
-            String callingPackage) {
-        return performReadOperation(callingPackage, () -> {
-            // TODO - implement
-            return new int[0];
-        });
-    }
-
-    @Override
-    public int getSenderParticipant(int messageId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getIntValueFromTableRow(INCOMING_MESSAGE_URI,
-                        SENDER_PARTICIPANT_ID_COLUMN, MESSAGE_ID_COLUMN, messageId));
-    }
-
-    @Override
-    public void deleteFileTransfer(int partId, String callingPackage) {
-        performWriteOperation(callingPackage,
-                () -> mContentResolver.delete(mMessageQueryHelper.getFileTransferUpdateUri(partId),
-                        null,
-                        null));
-    }
-
-    @Override
-    public int storeFileTransfer(int messageId, boolean isIncoming,
-            RcsFileTransferCreationParams fileTransferCreationParameters, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues contentValues = mMessageQueryHelper.getContentValuesForFileTransfer(
-                    fileTransferCreationParameters);
-            Uri uri = mContentResolver.insert(
-                    mMessageQueryHelper.getFileTransferInsertionUri(messageId), contentValues);
-
-            if (uri != null) {
-                return Integer.parseInt(uri.getLastPathSegment());
-            }
-
-            return TRANSACTION_FAILED;
-        });
-    }
-
-    @Override
-    public void setFileTransferSessionId(int partId, String sessionId, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), SESSION_ID_COLUMN,
-                sessionId,
-                "Could not set session ID for file transfer"));
-    }
-
-    @Override
-    public String getFileTransferSessionId(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(FILE_TRANSFER_URI,
-                        SESSION_ID_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferContentUri(int partId, Uri contentUri, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), CONTENT_URI_COLUMN,
-                contentUri, "Could not set content URI for file transfer"));
-    }
-
-    @Override
-    public Uri getFileTransferContentUri(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getUriValueFromTableRow(FILE_TRANSFER_URI,
-                        CONTENT_URI_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferContentType(int partId, String contentType, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), CONTENT_TYPE_COLUMN,
-                contentType, "Could not set content type for file transfer"));
-    }
-
-    @Override
-    public String getFileTransferContentType(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(FILE_TRANSFER_URI,
-                        CONTENT_TYPE_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferFileSize(int partId, long fileSize, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), FILE_SIZE_COLUMN,
-                fileSize,
-                "Could not set file size for file transfer"));
-    }
-
-    @Override
-    public long getFileTransferFileSize(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getLongValueFromTableRow(FILE_TRANSFER_URI,
-                        FILE_SIZE_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferTransferOffset(int partId, long transferOffset,
-            String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId),
-                SUCCESSFULLY_TRANSFERRED_BYTES,
-                transferOffset, "Could not set transfer offset for file transfer"));
-    }
-
-    @Override
-    public long getFileTransferTransferOffset(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getLongValueFromTableRow(FILE_TRANSFER_URI,
-                        SUCCESSFULLY_TRANSFERRED_BYTES,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferStatus(int partId, int transferStatus, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), TRANSFER_STATUS_COLUMN,
-                transferStatus, "Could not set transfer status for file transfer"));
-    }
-
-    @Override
-    public int getFileTransferStatus(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getIntValueFromTableRow(FILE_TRANSFER_URI, STATUS_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferWidth(int partId, int width, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), WIDTH_COLUMN, width,
-                "Could not set width of file transfer"));
-    }
-
-    @Override
-    public int getFileTransferWidth(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getIntValueFromTableRow(FILE_TRANSFER_URI, WIDTH_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferHeight(int partId, int height, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), HEIGHT_COLUMN, height,
-                "Could not set height of file transfer"));
-    }
-
-    @Override
-    public int getFileTransferHeight(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getIntValueFromTableRow(FILE_TRANSFER_URI, HEIGHT_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferLength(int partId, long length, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), DURATION_MILLIS_COLUMN,
-                length,
-                "Could not set length of file transfer"));
-    }
-
-    @Override
-    public long getFileTransferLength(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getLongValueFromTableRow(FILE_TRANSFER_URI,
-                        DURATION_MILLIS_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferPreviewUri(int partId, Uri uri, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), PREVIEW_URI_COLUMN, uri,
-                "Could not set preview URI of file transfer"));
-    }
-
-    @Override
-    public Uri getFileTransferPreviewUri(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getUriValueFromTableRow(FILE_TRANSFER_URI,
-                        DURATION_MILLIS_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public void setFileTransferPreviewType(int partId, String type, String callingPackage) {
-        performWriteOperation(callingPackage, () -> mMessageStoreUtil.updateValueOfProviderUri(
-                mMessageQueryHelper.getFileTransferUpdateUri(partId), PREVIEW_TYPE_COLUMN, type,
-                "Could not set preview type of file transfer"));
-    }
-
-    @Override
-    public String getFileTransferPreviewType(int partId, String callingPackage) {
-        return performReadOperation(callingPackage,
-                () -> mMessageStoreUtil.getStringValueFromTableRow(FILE_TRANSFER_URI,
-                        PREVIEW_TYPE_COLUMN,
-                        FILE_TRANSFER_ID_COLUMN, partId));
-    }
-
-    @Override
-    public int createGroupThreadNameChangedEvent(long timestamp, int threadId,
-            int originationParticipantId, String newName, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues eventSpecificValues = new ContentValues();
-            eventSpecificValues.put(NEW_NAME_COLUMN, newName);
-
-            return mEventQueryHelper.createGroupThreadEvent(NAME_CHANGED_EVENT_TYPE, timestamp,
-                    threadId, originationParticipantId, eventSpecificValues);
-        });
-    }
-
-    @Override
-    public int createGroupThreadIconChangedEvent(long timestamp, int threadId,
-            int originationParticipantId, Uri newIcon, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues eventSpecificValues = new ContentValues();
-            eventSpecificValues.put(NEW_ICON_URI_COLUMN,
-                    newIcon == null ? null : newIcon.toString());
-
-            return mEventQueryHelper.createGroupThreadEvent(ICON_CHANGED_EVENT_TYPE, timestamp,
-                    threadId, originationParticipantId, eventSpecificValues);
-        });
-    }
-
-    @Override
-    public int createGroupThreadParticipantJoinedEvent(long timestamp, int threadId,
-            int originationParticipantId, int participantId, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues eventSpecificValues = new ContentValues();
-            eventSpecificValues.put(DESTINATION_PARTICIPANT_ID_COLUMN, participantId);
-
-            return mEventQueryHelper.createGroupThreadEvent(PARTICIPANT_JOINED_EVENT_TYPE,
-                    timestamp,
-                    threadId, originationParticipantId, eventSpecificValues);
-        });
-    }
-
-    @Override
-    public int createGroupThreadParticipantLeftEvent(long timestamp, int threadId,
-            int originationParticipantId, int participantId, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues eventSpecificValues = new ContentValues();
-            eventSpecificValues.put(DESTINATION_PARTICIPANT_ID_COLUMN, participantId);
-
-            return mEventQueryHelper.createGroupThreadEvent(PARTICIPANT_LEFT_EVENT_TYPE, timestamp,
-                    threadId, originationParticipantId, eventSpecificValues);
-        });
-    }
-
-    @Override
-    public int createParticipantAliasChangedEvent(long timestamp, int participantId,
-            String newAlias, String callingPackage) {
-        return performWriteOperation(callingPackage, () -> {
-            ContentValues contentValues = new ContentValues(4);
-            contentValues.put(TIMESTAMP_COLUMN, timestamp);
-            contentValues.put(SOURCE_PARTICIPANT_ID_COLUMN, participantId);
-            contentValues.put(NEW_ALIAS_COLUMN, newAlias);
-
-            Uri uri = mContentResolver.insert(
-                    mEventQueryHelper.getParticipantEventInsertionUri(participantId),
-                    contentValues);
-
-            if (uri == null) {
-                throw new RemoteException(
-                        "Could not create RcsParticipantAliasChangedEvent with participant id: "
-                                + participantId);
-            }
-
-            return Integer.parseInt(uri.getLastPathSegment());
-        });
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/RcsMessageQueryHelper.java b/src/java/com/android/internal/telephony/ims/RcsMessageQueryHelper.java
deleted file mode 100644
index f8a0fe8..0000000
--- a/src/java/com/android/internal/telephony/ims/RcsMessageQueryHelper.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2017 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.ims;
-
-import static android.provider.Telephony.RcsColumns.CONTENT_AND_AUTHORITY;
-import static android.provider.Telephony.RcsColumns.Rcs1To1ThreadColumns.RCS_1_TO_1_THREAD_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.CONTENT_TYPE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.CONTENT_URI_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.DURATION_MILLIS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_SIZE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_TRANSFER_URI;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.FILE_TRANSFER_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.HEIGHT_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.PREVIEW_TYPE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.PREVIEW_URI_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.SESSION_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.SUCCESSFULLY_TRANSFERRED_BYTES;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.TRANSFER_STATUS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsFileTransferColumns.WIDTH_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.RCS_GROUP_THREAD_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.INCOMING_MESSAGE_URI;
-import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.INCOMING_MESSAGE_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.GLOBAL_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.MESSAGE_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.ORIGINATION_TIMESTAMP_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.STATUS_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageColumns.SUB_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsMessageDeliveryColumns.DELIVERY_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsOutgoingMessageColumns.OUTGOING_MESSAGE_URI;
-import static android.provider.Telephony.RcsColumns.RcsOutgoingMessageColumns.OUTGOING_MESSAGE_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_INCOMING;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_OUTGOING;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.UNIFIED_MESSAGE_URI;
-import static android.telephony.ims.RcsQueryContinuationToken.QUERY_CONTINUATION_TOKEN;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.telephony.ims.RcsFileTransferCreationParams;
-import android.telephony.ims.RcsMessageCreationParams;
-import android.telephony.ims.RcsMessageQueryResultParcelable;
-import android.telephony.ims.RcsQueryContinuationToken;
-
-import com.android.ims.RcsTypeIdPair;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A helper class focused on querying RCS messages from the
- * {@link com.android.providers.telephony.RcsProvider}
- */
-class RcsMessageQueryHelper {
-
-    private final ContentResolver mContentResolver;
-
-    RcsMessageQueryHelper(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-    }
-
-    RcsMessageQueryResultParcelable performMessageQuery(Bundle bundle) throws RemoteException {
-        RcsQueryContinuationToken continuationToken = null;
-        List<RcsTypeIdPair> messageTypeIdPairs = new ArrayList<>();
-
-        try (Cursor cursor = mContentResolver.query(UNIFIED_MESSAGE_URI, null, bundle, null)) {
-            if (cursor == null) {
-                throw new RemoteException("Could not perform message query, bundle: " + bundle);
-            }
-
-            while (cursor != null && cursor.moveToNext()) {
-                boolean isIncoming = cursor.getInt(cursor.getColumnIndex(MESSAGE_TYPE_COLUMN))
-                        == MESSAGE_TYPE_INCOMING;
-                int messageId = cursor.getInt(cursor.getColumnIndex(MESSAGE_ID_COLUMN));
-
-                messageTypeIdPairs.add(new RcsTypeIdPair(
-                        isIncoming ? MESSAGE_TYPE_INCOMING : MESSAGE_TYPE_OUTGOING, messageId));
-            }
-
-            if (cursor != null) {
-                Bundle cursorExtras = cursor.getExtras();
-                if (cursorExtras != null) {
-                    continuationToken =
-                            cursorExtras.getParcelable(QUERY_CONTINUATION_TOKEN);
-                }
-            }
-        }
-
-        return new RcsMessageQueryResultParcelable(continuationToken, messageTypeIdPairs);
-    }
-
-    void createContentValuesForGenericMessage(ContentValues contentValues, int threadId,
-            RcsMessageCreationParams rcsMessageCreationParams) {
-        contentValues.put(GLOBAL_ID_COLUMN, rcsMessageCreationParams.getRcsMessageGlobalId());
-        contentValues.put(SUB_ID_COLUMN, rcsMessageCreationParams.getSubId());
-        contentValues.put(STATUS_COLUMN, rcsMessageCreationParams.getMessageStatus());
-        contentValues.put(ORIGINATION_TIMESTAMP_COLUMN,
-                rcsMessageCreationParams.getOriginationTimestamp());
-        contentValues.put(RCS_THREAD_ID_COLUMN, threadId);
-    }
-
-    Uri getMessageInsertionUri(boolean isIncoming) {
-        return isIncoming ? INCOMING_MESSAGE_URI : OUTGOING_MESSAGE_URI;
-    }
-
-    Uri getMessageDeletionUri(int messageId, boolean isIncoming, int rcsThreadId, boolean isGroup) {
-        return CONTENT_AND_AUTHORITY.buildUpon().appendPath(
-                isGroup ? RCS_GROUP_THREAD_URI_PART : RCS_1_TO_1_THREAD_URI_PART).appendPath(
-                Integer.toString(rcsThreadId)).appendPath(
-                isIncoming ? INCOMING_MESSAGE_URI_PART : OUTGOING_MESSAGE_URI_PART).appendPath(
-                Integer.toString(messageId)).build();
-    }
-
-    Uri getMessageUpdateUri(int messageId, boolean isIncoming) {
-        return getMessageInsertionUri(isIncoming).buildUpon().appendPath(
-                Integer.toString(messageId)).build();
-    }
-
-    int[] getDeliveryParticipantsForMessage(int messageId) throws RemoteException {
-        int[] participantIds;
-
-        try (Cursor cursor = mContentResolver.query(getMessageDeliveryQueryUri(messageId), null,
-                null, null)) {
-            if (cursor == null) {
-                throw new RemoteException(
-                        "Could not query deliveries for message, messageId: " + messageId);
-            }
-
-            participantIds = new int[cursor.getCount()];
-
-            for (int i = 0; cursor.moveToNext(); i++) {
-                participantIds[i] = cursor.getInt(cursor.getColumnIndex(RCS_PARTICIPANT_ID_COLUMN));
-            }
-        }
-
-        return participantIds;
-    }
-
-    Uri getMessageDeliveryUri(int messageId, int participantId) {
-        return Uri.withAppendedPath(getMessageDeliveryQueryUri(messageId),
-                Integer.toString(participantId));
-    }
-
-    long getLongValueFromDelivery(int messageId, int participantId,
-            String columnName) throws RemoteException {
-        try (Cursor cursor = mContentResolver.query(getMessageDeliveryUri(messageId, participantId),
-                null, null, null)) {
-            if (cursor == null || !cursor.moveToFirst()) {
-                throw new RemoteException(
-                        "Could not read delivery for message: " + messageId + ", participant: "
-                                + participantId);
-            }
-
-            return cursor.getLong(cursor.getColumnIndex(columnName));
-        }
-    }
-
-    private Uri getMessageDeliveryQueryUri(int messageId) {
-        return getMessageInsertionUri(false).buildUpon().appendPath(
-                Integer.toString(messageId)).appendPath(DELIVERY_URI_PART).build();
-    }
-
-    ContentValues getContentValuesForFileTransfer(
-            RcsFileTransferCreationParams fileTransferCreationParameters) {
-        ContentValues contentValues = new ContentValues();
-        contentValues.put(SESSION_ID_COLUMN,
-                fileTransferCreationParameters.getRcsFileTransferSessionId());
-        contentValues.put(CONTENT_URI_COLUMN,
-                fileTransferCreationParameters.getContentUri().toString());
-        contentValues.put(CONTENT_TYPE_COLUMN, fileTransferCreationParameters.getContentMimeType());
-        contentValues.put(FILE_SIZE_COLUMN, fileTransferCreationParameters.getFileSize());
-        contentValues.put(SUCCESSFULLY_TRANSFERRED_BYTES,
-                fileTransferCreationParameters.getTransferOffset());
-        contentValues.put(TRANSFER_STATUS_COLUMN,
-                fileTransferCreationParameters.getFileTransferStatus());
-        contentValues.put(WIDTH_COLUMN, fileTransferCreationParameters.getWidth());
-        contentValues.put(HEIGHT_COLUMN, fileTransferCreationParameters.getHeight());
-        contentValues.put(DURATION_MILLIS_COLUMN,
-                fileTransferCreationParameters.getMediaDuration());
-        contentValues.put(PREVIEW_URI_COLUMN,
-                fileTransferCreationParameters.getPreviewUri().toString());
-        contentValues.put(PREVIEW_TYPE_COLUMN, fileTransferCreationParameters.getPreviewMimeType());
-
-        return contentValues;
-    }
-
-    Uri getFileTransferInsertionUri(int messageId) {
-        return UNIFIED_MESSAGE_URI.buildUpon().appendPath(Integer.toString(messageId)).appendPath(
-                FILE_TRANSFER_URI_PART).build();
-    }
-
-    Uri getFileTransferUpdateUri(int partId) {
-        return Uri.withAppendedPath(FILE_TRANSFER_URI, Integer.toString(partId));
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/RcsMessageStoreUtil.java b/src/java/com/android/internal/telephony/ims/RcsMessageStoreUtil.java
deleted file mode 100644
index 2b8f7b4..0000000
--- a/src/java/com/android/internal/telephony/ims/RcsMessageStoreUtil.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import static android.provider.Telephony.RcsColumns.RcsIncomingMessageColumns.INCOMING_MESSAGE_URI;
-import static android.provider.Telephony.RcsColumns.RcsOutgoingMessageColumns.OUTGOING_MESSAGE_URI;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.text.TextUtils;
-
-/**
- * Utility functions for {@link RcsMessageController}
- *
- * @hide
- */
-public class RcsMessageStoreUtil {
-    private ContentResolver mContentResolver;
-
-    RcsMessageStoreUtil(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-    }
-
-    int getIntValueFromTableRow(Uri tableUri, String valueColumn, String idColumn,
-            int idValue) throws RemoteException {
-        try (Cursor cursor = getValueFromTableRow(tableUri, valueColumn, idColumn, idValue)) {
-            if (cursor != null && cursor.moveToFirst()) {
-                return cursor.getInt(cursor.getColumnIndex(valueColumn));
-            } else {
-                throw new RemoteException("The row with (" + idColumn + " = " + idValue
-                        + ") could not be found in " + tableUri);
-            }
-        }
-    }
-
-    long getLongValueFromTableRow(Uri tableUri, String valueColumn, String idColumn,
-            int idValue) throws RemoteException {
-        try (Cursor cursor = getValueFromTableRow(tableUri, valueColumn, idColumn, idValue)) {
-            if (cursor != null && cursor.moveToFirst()) {
-                return cursor.getLong(cursor.getColumnIndex(valueColumn));
-            } else {
-                throw new RemoteException("The row with (" + idColumn + " = " + idValue
-                        + ") could not be found in " + tableUri);
-            }
-        }
-    }
-
-    double getDoubleValueFromTableRow(Uri tableUri, String valueColumn, String idColumn,
-            int idValue) throws RemoteException {
-        try (Cursor cursor = getValueFromTableRow(tableUri, valueColumn, idColumn, idValue)) {
-            if (cursor != null && cursor.moveToFirst()) {
-                return cursor.getDouble(cursor.getColumnIndex(valueColumn));
-            } else {
-                throw new RemoteException("The row with (" + idColumn + " = " + idValue
-                        + ") could not be found in " + tableUri);
-            }
-        }
-    }
-
-    String getStringValueFromTableRow(Uri tableUri, String valueColumn, String idColumn,
-            int idValue) throws RemoteException {
-        try (Cursor cursor = getValueFromTableRow(tableUri, valueColumn, idColumn, idValue)) {
-            if (cursor != null && cursor.moveToFirst()) {
-                return cursor.getString(cursor.getColumnIndex(valueColumn));
-            } else {
-                throw new RemoteException("The row with (" + idColumn + " = " + idValue
-                        + ") could not be found in " + tableUri);
-            }
-        }
-    }
-
-    Uri getUriValueFromTableRow(Uri tableUri, String valueColumn, String idColumn,
-            int idValue) throws RemoteException {
-        try (Cursor cursor = getValueFromTableRow(tableUri, valueColumn, idColumn, idValue)) {
-            if (cursor != null && cursor.moveToFirst()) {
-                String uriAsString = cursor.getString(cursor.getColumnIndex(valueColumn));
-
-                if (!TextUtils.isEmpty(uriAsString)) {
-                    return Uri.parse(uriAsString);
-                }
-                return null;
-            } else {
-                throw new RemoteException("The row with (" + idColumn + " = " + idValue
-                        + ") could not be found in " + tableUri);
-            }
-        }
-    }
-
-    void updateValueOfProviderUri(Uri uri, String valueColumn, int value, String errorMessage)
-            throws RemoteException {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(valueColumn, value);
-        performUpdate(uri, contentValues, errorMessage);
-    }
-
-    void updateValueOfProviderUri(Uri uri, String valueColumn, double value, String errorMessage)
-            throws RemoteException {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(valueColumn, value);
-        performUpdate(uri, contentValues, errorMessage);
-    }
-
-    void updateValueOfProviderUri(Uri uri, String valueColumn, long value, String errorMessage)
-            throws RemoteException {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(valueColumn, value);
-        performUpdate(uri, contentValues, errorMessage);
-    }
-
-    void updateValueOfProviderUri(Uri uri, String valueColumn, String value, String errorMessage)
-            throws RemoteException {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(valueColumn, value);
-        performUpdate(uri, contentValues, errorMessage);
-    }
-
-    void updateValueOfProviderUri(Uri uri, String valueColumn, Uri value, String errorMessage)
-            throws RemoteException {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(valueColumn, value == null ? null : value.toString());
-        performUpdate(uri, contentValues, errorMessage);
-    }
-
-    private void performUpdate(Uri uri, ContentValues contentValues, String errorMessage)
-            throws RemoteException {
-        int updateCount = mContentResolver.update(uri, contentValues, null, null);
-
-        // TODO - convert remote exceptions to return values.
-        if (updateCount <= 0) {
-            throw new RemoteException(errorMessage);
-        }
-    }
-
-    private Cursor getValueFromTableRow(Uri tableUri, String valueColumn, String idColumn,
-            int idValue) {
-        return mContentResolver.query(tableUri, new String[]{valueColumn}, idColumn + "=?",
-                new String[]{Integer.toString(idValue)}, null);
-    }
-
-    static Uri getMessageTableUri(boolean isIncoming) {
-        return isIncoming ? INCOMING_MESSAGE_URI : OUTGOING_MESSAGE_URI;
-    }
-
-
-}
diff --git a/src/java/com/android/internal/telephony/ims/RcsParticipantQueryHelper.java b/src/java/com/android/internal/telephony/ims/RcsParticipantQueryHelper.java
deleted file mode 100644
index 11f9e3b..0000000
--- a/src/java/com/android/internal/telephony/ims/RcsParticipantQueryHelper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_URI;
-import static android.telephony.ims.RcsQueryContinuationToken.QUERY_CONTINUATION_TOKEN;
-
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.telephony.ims.RcsParticipantQueryResultParcelable;
-import android.telephony.ims.RcsQueryContinuationToken;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class RcsParticipantQueryHelper {
-    private final ContentResolver mContentResolver;
-
-    RcsParticipantQueryHelper(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-    }
-
-    RcsParticipantQueryResultParcelable performParticipantQuery(Bundle bundle)
-            throws RemoteException {
-        RcsQueryContinuationToken continuationToken = null;
-        List<Integer> participantList = new ArrayList<>();
-
-        try (Cursor cursor = mContentResolver.query(RCS_PARTICIPANT_URI, null, bundle, null)) {
-            if (cursor == null) {
-                throw new RemoteException("Could not perform participant query, bundle: " + bundle);
-            }
-
-            while (cursor.moveToNext()) {
-                participantList.add(
-                        cursor.getInt(cursor.getColumnIndex(RCS_PARTICIPANT_ID_COLUMN)));
-            }
-
-            Bundle cursorExtras = cursor.getExtras();
-            if (cursorExtras != null) {
-                continuationToken = cursorExtras.getParcelable(QUERY_CONTINUATION_TOKEN);
-            }
-        }
-
-        return new RcsParticipantQueryResultParcelable(continuationToken, participantList);
-    }
-
-    static Uri getUriForParticipant(int participantId) {
-        return Uri.withAppendedPath(RCS_PARTICIPANT_URI, Integer.toString(participantId));
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/RcsPermissions.java b/src/java/com/android/internal/telephony/ims/RcsPermissions.java
deleted file mode 100644
index 5ccdc12..0000000
--- a/src/java/com/android/internal/telephony/ims/RcsPermissions.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import android.Manifest;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.os.Binder;
-
-class RcsPermissions {
-    static void checkReadPermissions(Context context, String callingPackage) {
-        int pid = Binder.getCallingPid();
-        int uid = Binder.getCallingUid();
-
-        context.enforcePermission(Manifest.permission.READ_SMS, pid, uid, null);
-
-        checkOp(context, uid, callingPackage, AppOpsManager.OPSTR_READ_SMS);
-    }
-
-    static void checkWritePermissions(Context context, String callingPackage) {
-        int uid = Binder.getCallingUid();
-
-        checkOp(context, uid, callingPackage, AppOpsManager.OPSTR_WRITE_SMS);
-    }
-
-    /**
-     * Notes the provided op, but throws even if the op mode is {@link AppOpsManager.MODE_IGNORED}.
-     * <p>
-     * {@link AppOpsManager.OPSTR_WRITE_SMS} defaults to {@link AppOpsManager.MODE_IGNORED} to avoid
-     * crashing applications written before the app op was introduced. Since this is a new API,
-     * consumers should be aware of the permission requirements, and we should be safe to throw a
-     * {@link SecurityException} instead of providing a dummy value (which could cause unexpected
-     * application behavior and possible loss of user data). {@link AppOpsManager.OPSTR_READ_SMS} is
-     * not normally in {@link AppOpsManager.MODE_IGNORED}, but we maintain the same behavior for
-     * consistency with handling of write permissions.
-     */
-    private static void checkOp(Context context, int uid, String callingPackage, String op) {
-        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-
-        int mode = appOps.noteOp(op, uid, callingPackage);
-
-        if (mode != AppOpsManager.MODE_ALLOWED) {
-            throw new SecurityException(op + " not allowed for " + callingPackage);
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/RcsThreadHelper.java b/src/java/com/android/internal/telephony/ims/RcsThreadHelper.java
deleted file mode 100644
index 6d95430..0000000
--- a/src/java/com/android/internal/telephony/ims/RcsThreadHelper.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import static android.provider.Telephony.RcsColumns.Rcs1To1ThreadColumns.RCS_1_TO_1_THREAD_URI;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_ICON_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_NAME_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.RCS_GROUP_THREAD_URI;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsParticipantColumns.RCS_PARTICIPANT_URI_PART;
-import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsThreadColumns.RCS_THREAD_URI;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_1_TO_1;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_GROUP;
-import static android.telephony.ims.RcsQueryContinuationToken.QUERY_CONTINUATION_TOKEN;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.telephony.ims.RcsQueryContinuationToken;
-import android.telephony.ims.RcsThreadQueryResultParcelable;
-
-import com.android.ims.RcsTypeIdPair;
-
-import java.util.ArrayList;
-import java.util.List;
-
-// TODO optimize considering returned threads do not contain query information
-
-/**
- * A helper class focused on querying RCS threads from the
- * {@link com.android.providers.telephony.RcsProvider}
- */
-class RcsThreadHelper {
-    private static final int THREAD_ID_INDEX_IN_INSERTION_URI = 1;
-
-    private final ContentResolver mContentResolver;
-    private final RcsParticipantQueryHelper mParticipantQueryHelper;
-
-    RcsThreadHelper(ContentResolver contentResolver,
-            RcsParticipantQueryHelper participantQueryHelper) {
-        mContentResolver = contentResolver;
-        mParticipantQueryHelper = participantQueryHelper;
-    }
-
-    RcsThreadQueryResultParcelable performThreadQuery(Bundle bundle) throws RemoteException {
-        RcsQueryContinuationToken continuationToken = null;
-        List<RcsTypeIdPair> rcsThreadIdList = new ArrayList<>();
-        try (Cursor cursor = mContentResolver.query(RCS_THREAD_URI, null, bundle, null)) {
-            if (cursor == null) {
-                throw new RemoteException("Could not perform thread query, bundle: " + bundle);
-            }
-
-            while (cursor.moveToNext()) {
-                boolean isGroup = cursor.getInt(cursor.getColumnIndex(THREAD_TYPE_COLUMN))
-                        == THREAD_TYPE_GROUP;
-
-                if (isGroup) {
-                    int threadId = cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN));
-                    rcsThreadIdList.add(new RcsTypeIdPair(THREAD_TYPE_GROUP, threadId));
-                } else {
-                    int threadId = cursor.getInt(cursor.getColumnIndex(RCS_THREAD_ID_COLUMN));
-                    rcsThreadIdList.add(new RcsTypeIdPair(THREAD_TYPE_1_TO_1, threadId));
-                }
-            }
-
-            // If there is a continuation token, add it to the query result.
-            Bundle cursorExtras = cursor.getExtras();
-            if (cursorExtras != null) {
-                continuationToken = cursorExtras.getParcelable(QUERY_CONTINUATION_TOKEN);
-            }
-        }
-        return new RcsThreadQueryResultParcelable(continuationToken, rcsThreadIdList);
-    }
-
-    int create1To1Thread(int participantId) throws RemoteException {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(RCS_PARTICIPANT_ID_COLUMN, participantId);
-        Uri insertionUri = mContentResolver.insert(RCS_1_TO_1_THREAD_URI, contentValues);
-
-        if (insertionUri == null) {
-            throw new RemoteException("Rcs1To1Thread creation failed");
-        }
-
-        String threadIdAsString = insertionUri.getLastPathSegment();
-        int threadId = Integer.parseInt(threadIdAsString);
-
-        if (threadId <= 0) {
-            throw new RemoteException("Rcs1To1Thread creation failed");
-        }
-
-        return threadId;
-    }
-
-    int createGroupThread(String groupName, Uri groupIcon) throws RemoteException {
-        // Create the group
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(GROUP_NAME_COLUMN, groupName);
-        if (groupIcon != null) {
-            contentValues.put(GROUP_ICON_COLUMN, groupIcon.toString());
-        }
-
-        Uri groupUri = mContentResolver.insert(RCS_GROUP_THREAD_URI,
-                contentValues);
-        if (groupUri == null) {
-            throw new RemoteException("RcsGroupThread creation failed");
-        }
-
-        // get the thread id from group URI
-        String threadIdAsString = groupUri.getPathSegments().get(THREAD_ID_INDEX_IN_INSERTION_URI);
-        int threadId = Integer.parseInt(threadIdAsString);
-
-        return threadId;
-    }
-
-    void addParticipantToGroupThread(int rcsThreadId, int participantId) {
-        ContentValues contentValues = new ContentValues(2);
-        contentValues.put(RCS_THREAD_ID_COLUMN, rcsThreadId);
-        contentValues.put(RCS_PARTICIPANT_ID_COLUMN, participantId);
-
-        mContentResolver.insert(getAllParticipantsInThreadUri(rcsThreadId), contentValues);
-    }
-
-    static Uri get1To1ThreadUri(int rcsThreadId) {
-        return Uri.withAppendedPath(RCS_1_TO_1_THREAD_URI, Integer.toString(rcsThreadId));
-    }
-
-    static Uri getGroupThreadUri(int rcsThreadId) {
-        return Uri.withAppendedPath(RCS_GROUP_THREAD_URI, Integer.toString(rcsThreadId));
-    }
-
-    static Uri getAllParticipantsInThreadUri(int rcsThreadId) {
-        return RCS_GROUP_THREAD_URI.buildUpon().appendPath(Integer.toString(rcsThreadId))
-                .appendPath(RCS_PARTICIPANT_URI_PART).build();
-    }
-
-    static Uri getParticipantInThreadUri(int rcsThreadId, int participantId) {
-        return RCS_GROUP_THREAD_URI.buildUpon().appendPath(Integer.toString(rcsThreadId))
-                .appendPath(RCS_PARTICIPANT_URI_PART).appendPath(Integer.toString(
-                        participantId)).build();
-    }
-}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsExternalCall.java b/src/java/com/android/internal/telephony/imsphone/ImsExternalCall.java
index 7b6162d..b5d6b18 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsExternalCall.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsExternalCall.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.imsphone;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.telephony.ims.ImsExternalCallState;
 
 import com.android.internal.telephony.Call;
@@ -60,6 +60,12 @@
 
     }
 
+    @Override
+    public void hangup(@android.telecom.Call.RejectReason int rejectReason)
+            throws CallStateException {
+        // tumbleweed
+    }
+
     /**
      * Sets the call state to active.
      */
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsExternalConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsExternalConnection.java
index cd5c83d..b29acdb 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsExternalConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsExternalConnection.java
@@ -16,7 +16,13 @@
 
 package com.android.internal.telephony.imsphone;
 
-import com.android.internal.R;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.net.Uri;
+import android.telecom.PhoneAccount;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ims.ImsExternalCallState;
+
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
@@ -24,13 +30,6 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.UUSInfo;
 
-import android.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.net.Uri;
-import android.telecom.PhoneAccount;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.ims.ImsExternalCallState;
-
 import java.util.Collections;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 7a863d0..45d94d0 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.telephony.imsphone;
 
+import static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE;
+import static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_TITLE;
+
 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC;
 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr;
 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC;
@@ -24,6 +27,7 @@
 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL;
 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO;
 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BIC_ACR;
 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
@@ -37,12 +41,12 @@
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE;
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -58,13 +62,12 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.ResultReceiver;
-import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.sysprop.TelephonyProperties;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CarrierConfigManager;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -75,15 +78,15 @@
 import android.telephony.ims.ImsSsData;
 import android.telephony.ims.ImsSsInfo;
 import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.stub.ImsUtImplBase;
 import android.text.TextUtils;
+import android.util.LocalLog;
 
-import com.android.ims.FeatureConnector;
 import com.android.ims.ImsEcbm;
 import com.android.ims.ImsEcbmStateListener;
 import com.android.ims.ImsException;
 import com.android.ims.ImsManager;
 import com.android.ims.ImsUtInterface;
-import com.android.ims.RcsFeatureManager;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallForwardInfo;
@@ -100,13 +103,16 @@
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyComponentFactory;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.dataconnection.TransportManager;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.gsm.GsmMmiCode;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.util.NotificationChannelController;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -137,7 +143,7 @@
     static final int CANCEL_ECM_TIMER  = 1; // cancel Ecm timer
 
     // Default Emergency Callback Mode exit timer
-    private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
+    private static final long DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
 
     public static class ImsDialArgs extends DialArgs {
         public static class Builder extends DialArgs.Builder<ImsDialArgs.Builder> {
@@ -202,9 +208,6 @@
     @UnsupportedAppUsage
     private ServiceState mSS = new ServiceState();
 
-    private RcsFeatureManager mRcsManager;
-    private final FeatureConnector<RcsFeatureManager> mRcsManagerConnector;
-
     // To redial silently through GSM or CDMA when dialing through IMS fails
     private String mLastDialString;
 
@@ -216,10 +219,16 @@
 
     private final RegistrantList mSilentRedialRegistrants = new RegistrantList();
 
-    private int mImsRegistrationState = RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED;
+    private final LocalLog mRegLocalLog = new LocalLog(100);
+    private TelephonyMetrics mMetrics;
+
+    // The helper class to receive and store the MmTel registration status updated.
+    private ImsRegistrationCallbackHelper mImsMmTelRegistrationHelper;
 
     private boolean mRoaming = false;
 
+    private boolean mIsInImsEcm = false;
+
     // List of Registrants to send supplementary service notifications to.
     private RegistrantList mSsnRegistrants = new RegistrantList();
 
@@ -255,6 +264,11 @@
     }
 
     @Override
+    public int getEmergencyNumberDbVersion() {
+        return getEmergencyNumberTracker().getEmergencyNumberDbVersion();
+    }
+
+    @Override
     public EmergencyNumberTracker getEmergencyNumberTracker() {
         return mDefaultPhone.getEmergencyNumberTracker();
     }
@@ -309,6 +323,11 @@
 
         mPhoneId = mDefaultPhone.getPhoneId();
 
+        mMetrics = TelephonyMetrics.getInstance();
+
+        mImsMmTelRegistrationHelper = new ImsRegistrationCallbackHelper(mMmTelRegistrationUpdate,
+                context.getMainExecutor());
+
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
         mWakeLock.setReferenceCounted(false);
@@ -329,35 +348,6 @@
         mDefaultPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
         // Force initial roaming state update later, on EVENT_CARRIER_CONFIG_CHANGED.
         // Settings provider or CarrierConfig may not be loaded now.
-
-        mRcsManagerConnector = new FeatureConnector<RcsFeatureManager>(mContext, mPhoneId,
-                new FeatureConnector.Listener<RcsFeatureManager>() {
-                    @Override
-                    public boolean isSupported() {
-                        if (!ImsManager.isImsSupportedOnDevice(mContext)) {
-                            return false;
-                        }
-                        if (!RcsFeatureManager.isRcsUceSupportedByCarrier(mContext, mPhoneId)) {
-                            return false;
-                        }
-                        return true;
-                    }
-
-                    @Override
-                    public RcsFeatureManager getFeatureManager() {
-                        return new RcsFeatureManager(mContext, mPhoneId);
-                    }
-
-                    @Override
-                    public void connectionReady(RcsFeatureManager manager) throws ImsException {
-                        mRcsManager = manager;
-                    }
-
-                    @Override
-                    public void connectionUnavailable() {
-                    }
-                }, mContext.getMainExecutor(), "ImsPhone");
-        mRcsManagerConnector.connect();
     }
 
     //todo: get rid of this function. It is not needed since parentPhone obj never changes
@@ -380,8 +370,6 @@
             }
             mDefaultPhone.unregisterForServiceStateChanged(this);
         }
-
-        mRcsManagerConnector.disconnect();
     }
 
     @UnsupportedAppUsage
@@ -396,7 +384,7 @@
         boolean isVoiceRegStateChanged = false;
 
         synchronized (this) {
-            isVoiceRegStateChanged = mSS.getVoiceRegState() != state;
+            isVoiceRegStateChanged = mSS.getState() != state;
             mSS.setVoiceRegState(state);
         }
         updateDataServiceState();
@@ -628,8 +616,18 @@
                 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) {
                     if (DBG) logd("MmiCode 2: accept ringing call");
                     mCT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE);
-                } else {
-                    if (DBG) logd("MmiCode 2: holdActiveCall");
+                } else if (getBackgroundCall().getState() == ImsPhoneCall.State.HOLDING) {
+                    // If there's an active ongoing call as well, hold it and the background one
+                    // should automatically unhold. Otherwise just unhold the background call.
+                    if (getForegroundCall().getState() != ImsPhoneCall.State.IDLE) {
+                        if (DBG) logd("MmiCode 2: switch holding and active");
+                        mCT.holdActiveCall();
+                    } else {
+                        if (DBG) logd("MmiCode 2: unhold held call");
+                        mCT.unholdHeldCall();
+                    }
+                } else if (getForegroundCall().getState() != ImsPhoneCall.State.IDLE) {
+                    if (DBG) logd("MmiCode 2: hold active call");
                     mCT.holdActiveCall();
                 }
             } catch (CallStateException e) {
@@ -735,12 +733,18 @@
     }
 
     @Override
+    public boolean isInImsEcm() {
+        return mIsInImsEcm;
+    }
+
+    @Override
     public boolean isInEcm() {
         return mDefaultPhone.isInEcm();
     }
 
     @Override
     public void setIsInEcm(boolean isInEcm){
+        mIsInImsEcm = isInEcm;
         mDefaultPhone.setIsInEcm(isInEcm);
     }
 
@@ -765,6 +769,18 @@
     }
 
     @Override
+    public Connection startConference(String[] participantsToDial, DialArgs dialArgs)
+            throws CallStateException {
+         ImsDialArgs.Builder imsDialArgsBuilder;
+         if (!(dialArgs instanceof ImsDialArgs)) {
+             imsDialArgsBuilder = ImsDialArgs.Builder.from(dialArgs);
+         } else {
+             imsDialArgsBuilder = ImsDialArgs.Builder.from((ImsDialArgs) dialArgs);
+         }
+         return mCT.startConference(participantsToDial, imsDialArgsBuilder.build());
+    }
+
+    @Override
     public Connection dial(String dialString, DialArgs dialArgs) throws CallStateException {
         return dialInternal(dialString, dialArgs, null);
     }
@@ -1113,21 +1129,23 @@
 
     private int getCBTypeFromFacility(String facility) {
         if (CB_FACILITY_BAOC.equals(facility)) {
-            return ImsUtInterface.CB_BAOC;
+            return ImsUtImplBase.CALL_BARRING_ALL_OUTGOING;
         } else if (CB_FACILITY_BAOIC.equals(facility)) {
-            return ImsUtInterface.CB_BOIC;
+            return ImsUtImplBase.CALL_BARRING_OUTGOING_INTL;
         } else if (CB_FACILITY_BAOICxH.equals(facility)) {
-            return ImsUtInterface.CB_BOIC_EXHC;
+            return ImsUtImplBase.CALL_BARRING_OUTGOING_INTL_EXCL_HOME;
         } else if (CB_FACILITY_BAIC.equals(facility)) {
-            return ImsUtInterface.CB_BAIC;
+            return ImsUtImplBase.CALL_BARRING_ALL_INCOMING;
         } else if (CB_FACILITY_BAICr.equals(facility)) {
-            return ImsUtInterface.CB_BIC_WR;
+            return ImsUtImplBase.CALL_BLOCKING_INCOMING_WHEN_ROAMING;
         } else if (CB_FACILITY_BA_ALL.equals(facility)) {
-            return ImsUtInterface.CB_BA_ALL;
+            return ImsUtImplBase.CALL_BARRING_ALL;
         } else if (CB_FACILITY_BA_MO.equals(facility)) {
-            return ImsUtInterface.CB_BA_MO;
+            return ImsUtImplBase.CALL_BARRING_OUTGOING_ALL_SERVICES;
         } else if (CB_FACILITY_BA_MT.equals(facility)) {
-            return ImsUtInterface.CB_BA_MT;
+            return ImsUtImplBase.CALL_BARRING_INCOMING_ALL_SERVICES;
+        } else if (CB_FACILITY_BIC_ACR.equals(facility)) {
+            return ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING;
         }
 
         return 0;
@@ -1165,7 +1183,7 @@
 
     @Override
     public void setCallBarring(String facility, boolean lockState, String password,
-            Message onComplete,  int serviceClass) {
+            Message onComplete, int serviceClass) {
         if (DBG) {
             logd("setCallBarring facility=" + facility
                     + ", lockState=" + lockState + ", serviceClass = " + serviceClass);
@@ -1183,9 +1201,8 @@
 
         try {
             ImsUtInterface ut = mCT.getUtInterface();
-            // password is not required with Ut interface
             ut.updateCallBarring(getCBTypeFromFacility(facility), action,
-                    resp, null,  serviceClass);
+                    resp, null, serviceClass, password);
         } catch (ImsException e) {
             sendErrorResponse(onComplete, e);
         }
@@ -1437,20 +1454,15 @@
             cfInfos = new CallForwardInfo[infos.length];
         }
 
-        IccRecords r = mDefaultPhone.getIccRecords();
         if (infos == null || infos.length == 0) {
-            if (r != null) {
-                // Assume the default is not active
-                // Set unconditional CFF in SIM to false
-                setVoiceCallForwardingFlag(r, 1, false, null);
-            }
+            // Assume the default is not active
+            // Set unconditional CFF in SIM to false
+            setVoiceCallForwardingFlag(getIccRecords(), 1, false, null);
         } else {
             for (int i = 0, s = infos.length; i < s; i++) {
                 if (infos[i].getCondition() == ImsUtInterface.CDIV_CF_UNCONDITIONAL) {
-                    if (r != null) {
-                        setVoiceCallForwardingFlag(r, 1, (infos[i].getStatus() == 1),
-                                infos[i].getNumber());
-                    }
+                    setVoiceCallForwardingFlag(getIccRecords(), 1, (infos[i].getStatus() == 1),
+                        infos[i].getNumber());
                 }
                 cfInfos[i] = getCallForwardInfo(infos[i]);
             }
@@ -1498,7 +1510,7 @@
         if (mSS != null && mDefaultPhone.getServiceStateTracker() != null
                 && mDefaultPhone.getServiceStateTracker().mSS != null) {
             ServiceState ss = mDefaultPhone.getServiceStateTracker().mSS;
-            mSS.setDataRegState(ss.getDataRegState());
+            mSS.setDataRegState(ss.getDataRegistrationState());
             List<NetworkRegistrationInfo> nriList =
                     ss.getNetworkRegistrationInfoListForDomain(NetworkRegistrationInfo.DOMAIN_PS);
             for (NetworkRegistrationInfo nri : nriList) {
@@ -1517,10 +1529,9 @@
         if (DBG) logd("handleMessage what=" + msg.what);
         switch (msg.what) {
             case EVENT_SET_CALL_FORWARD_DONE:
-                IccRecords r = mDefaultPhone.getIccRecords();
                 Cf cf = (Cf) ar.userObj;
-                if (cf.mIsCfu && ar.exception == null && r != null) {
-                    setVoiceCallForwardingFlag(r, 1, msg.arg1 == 1, cf.mSetCfNumber);
+                if (cf.mIsCfu && ar.exception == null) {
+                    setVoiceCallForwardingFlag(getIccRecords(), 1, msg.arg1 == 1, cf.mSetCfNumber);
                 }
                 sendResponse(cf.mOnComplete, null, ar.exception);
                 break;
@@ -1661,8 +1672,8 @@
 
             // Post this runnable so we will automatically exit
             // if no one invokes exitEmergencyCallbackMode() directly.
-            long delayInMillis = SystemProperties.getLong(
-                    TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+            long delayInMillis = TelephonyProperties.ecm_exit_timer()
+                    .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
             postDelayed(mExitEcmRunnable, delayInMillis);
             // We don't want to go to sleep while in Ecm
             mWakeLock.acquire();
@@ -1707,8 +1718,8 @@
                 ((GsmCdmaPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.TRUE);
                 break;
             case RESTART_ECM_TIMER:
-                long delayInMillis = SystemProperties.getLong(
-                        TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+                long delayInMillis = TelephonyProperties.ecm_exit_timer()
+                        .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
                 postDelayed(mExitEcmRunnable, delayInMillis);
                 ((GsmCdmaPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.FALSE);
                 break;
@@ -1765,7 +1776,7 @@
 
     @Override
     public void getImsRegistrationState(Consumer<Integer> callback) {
-        callback.accept(mImsRegistrationState);
+        callback.accept(mImsMmTelRegistrationHelper.getImsRegistrationState());
     }
 
     @Override
@@ -1775,18 +1786,20 @@
 
     @Override
     public boolean isImsRegistered() {
-        return mImsRegistrationState == RegistrationManager.REGISTRATION_STATE_REGISTERED;
+        return mImsMmTelRegistrationHelper.isImsRegistered();
     }
 
     // Not used, but not removed due to UnsupportedAppUsage tag.
     @UnsupportedAppUsage
     public void setImsRegistered(boolean isRegistered) {
-        mImsRegistrationState = isRegistered ? RegistrationManager.REGISTRATION_STATE_REGISTERED :
-                RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED;
+        mImsMmTelRegistrationHelper.updateRegistrationState(
+                isRegistered ? RegistrationManager.REGISTRATION_STATE_REGISTERED :
+                        RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
     }
 
     public void setImsRegistrationState(@RegistrationManager.ImsRegistrationState int value) {
-        mImsRegistrationState = value;
+        if (DBG) logd("setImsRegistrationState: " + value);
+        mImsMmTelRegistrationHelper.updateRegistrationState(value);
     }
 
     @Override
@@ -1802,16 +1815,19 @@
                 // Default result code (as passed to sendOrderedBroadcast)
                 // means that intent was not received by WfcSettings.
 
-                CharSequence title = intent.getCharSequenceExtra(EXTRA_KEY_ALERT_TITLE);
-                CharSequence messageAlert = intent.getCharSequenceExtra(EXTRA_KEY_ALERT_MESSAGE);
-                CharSequence messageNotification = intent.getCharSequenceExtra(EXTRA_KEY_NOTIFICATION_MESSAGE);
+                CharSequence title =
+                        intent.getCharSequenceExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE);
+                CharSequence messageAlert =
+                        intent.getCharSequenceExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE);
+                CharSequence messageNotification =
+                        intent.getCharSequenceExtra(EXTRA_KEY_NOTIFICATION_MESSAGE);
 
                 Intent resultIntent = new Intent(Intent.ACTION_MAIN);
                 resultIntent.setClassName("com.android.settings",
                         "com.android.settings.Settings$WifiCallingSettingsActivity");
                 resultIntent.putExtra(EXTRA_KEY_ALERT_SHOW, true);
-                resultIntent.putExtra(EXTRA_KEY_ALERT_TITLE, title);
-                resultIntent.putExtra(EXTRA_KEY_ALERT_MESSAGE, messageAlert);
+                resultIntent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE, title);
+                resultIntent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE, messageAlert);
                 PendingIntent resultPendingIntent =
                         PendingIntent.getActivity(
                                 mContext,
@@ -1936,9 +1952,10 @@
 
             // If WfcSettings are active then alert will be shown
             // otherwise notification will be added.
-            Intent intent = new Intent(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
-            intent.putExtra(EXTRA_KEY_ALERT_TITLE, title);
-            intent.putExtra(EXTRA_KEY_ALERT_MESSAGE, messageAlert);
+            Intent intent = new Intent(
+                    android.telephony.ims.ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR);
+            intent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE, title);
+            intent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE, messageAlert);
             intent.putExtra(EXTRA_KEY_NOTIFICATION_MESSAGE, messageNotification);
             mContext.sendOrderedBroadcast(intent, null, mResultReceiver,
                     null, Activity.RESULT_OK, null, null);
@@ -1991,8 +2008,8 @@
         if (mRoaming == newRoamingState) {
             return;
         }
-        boolean isInService = (ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
-                || ss.getDataRegState() == ServiceState.STATE_IN_SERVICE);
+        boolean isInService = (ss.getState() == ServiceState.STATE_IN_SERVICE
+                || ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE);
         // If we are not IN_SERVICE for voice or data, ignore change roaming state, as we always
         // move to home in this case.
         if (!isInService) {
@@ -2043,8 +2060,69 @@
                 && psInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN;
     }
 
+    public RegistrationManager.RegistrationCallback getImsMmTelRegistrationCallback() {
+        return mImsMmTelRegistrationHelper.getCallback();
+    }
+
+    /**
+     * Reset the IMS registration state.
+     */
+    public void resetImsRegistrationState() {
+        if (DBG) logd("resetImsRegistrationState");
+        mImsMmTelRegistrationHelper.reset();
+    }
+
+    private ImsRegistrationCallbackHelper.ImsRegistrationUpdate mMmTelRegistrationUpdate = new
+            ImsRegistrationCallbackHelper.ImsRegistrationUpdate() {
+        @Override
+        public void handleImsRegistered(int imsRadioTech) {
+            if (DBG) {
+                logd("onImsMmTelConnected imsRadioTech="
+                        + AccessNetworkConstants.transportTypeToString(imsRadioTech));
+            }
+            mRegLocalLog.log("onImsMmTelConnected imsRadioTech="
+                    + AccessNetworkConstants.transportTypeToString(imsRadioTech));
+            setServiceState(ServiceState.STATE_IN_SERVICE);
+            mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null);
+        }
+
+        @Override
+        public void handleImsRegistering(int imsRadioTech) {
+            if (DBG) {
+                logd("onImsMmTelProgressing imsRadioTech="
+                        + AccessNetworkConstants.transportTypeToString(imsRadioTech));
+            }
+            mRegLocalLog.log("onImsMmTelProgressing imsRadioTech="
+                    + AccessNetworkConstants.transportTypeToString(imsRadioTech));
+            setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
+            mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.PROGRESSING,
+                    null);
+        }
+
+        @Override
+        public void handleImsUnregistered(ImsReasonInfo imsReasonInfo) {
+            if (DBG) logd("onImsMmTelDisconnected imsReasonInfo=" + imsReasonInfo);
+            mRegLocalLog.log("onImsMmTelDisconnected imsRadioTech=" + imsReasonInfo);
+            setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
+            processDisconnectReason(imsReasonInfo);
+            mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.DISCONNECTED,
+                    imsReasonInfo);
+        }
+
+        @Override
+        public void handleImsSubscriberAssociatedUriChanged(Uri[] uris) {
+            if (DBG) logd("handleImsSubscriberAssociatedUriChanged");
+            setCurrentSubscriberUris(uris);
+        }
+    };
+
+    public IccRecords getIccRecords() {
+        return mDefaultPhone.getIccRecords();
+    }
+
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
         pw.println("ImsPhone extends:");
         super.dump(fd, pw, args);
         pw.flush();
@@ -2058,9 +2136,14 @@
         pw.println("  mIsPhoneInEcmState = " + isInEcm());
         pw.println("  mEcmExitRespRegistrant = " + mEcmExitRespRegistrant);
         pw.println("  mSilentRedialRegistrants = " + mSilentRedialRegistrants);
-        pw.println("  mImsRegistrationState = " + mImsRegistrationState);
+        pw.println("  mImsMmTelRegistrationState = "
+                + mImsMmTelRegistrationHelper.getImsRegistrationState());
         pw.println("  mRoaming = " + mRoaming);
         pw.println("  mSsnRegistrants = " + mSsnRegistrants);
+        pw.println(" Registration Log:");
+        pw.increaseIndent();
+        mRegLocalLog.dump(pw);
+        pw.decreaseIndent();
         pw.flush();
     }
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
index 5e670f4..d8df4e8 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
@@ -22,10 +22,9 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.RegistrantList;
-import android.os.SystemProperties;
+import android.sysprop.TelephonyProperties;
 import android.telephony.CallQuality;
 import android.telephony.NetworkScanRequest;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.ims.ImsReasonInfo;
@@ -41,9 +40,9 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneNotifier;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.dataconnection.DataConnection;
 import com.android.internal.telephony.uicc.IccFileHandler;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -169,11 +168,6 @@
     }
 
     @Override
-    public boolean getCallForwardingIndicator() {
-        return false;
-    }
-
-    @Override
     public List<? extends MmiCode> getPendingMmiCodes() {
         return new ArrayList<MmiCode>(0);
     }
@@ -237,10 +231,9 @@
         Rlog.v(LOG_TAG, "canDial(): serviceState = " + serviceState);
         if (serviceState == ServiceState.STATE_POWER_OFF) return false;
 
-        String disableCall = SystemProperties.get(
-                TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
+        boolean disableCall = TelephonyProperties.disable_call().orElse(false);
         Rlog.v(LOG_TAG, "canDial(): disableCall = " + disableCall);
-        if (disableCall.equals("true")) return false;
+        if (disableCall) return false;
 
         Rlog.v(LOG_TAG, "canDial(): ringingCall: " + getRingingCall().getState());
         Rlog.v(LOG_TAG, "canDial(): foregndCall: " + getForegroundCall().getState());
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java
index f4fdebd..c9e5096 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java
@@ -16,21 +16,20 @@
 
 package com.android.internal.telephony.imsphone;
 
-import android.annotation.UnsupportedAppUsage;
-import com.android.ims.internal.ConferenceParticipant;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.telephony.DisconnectCause;
-import android.telephony.Rlog;
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.util.Log;
 
 import com.android.ims.ImsCall;
 import com.android.ims.ImsException;
+import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
+import com.android.telephony.Rlog;
 
 import java.util.List;
 
@@ -124,6 +123,12 @@
     }
 
     @Override
+    public void hangup(@android.telecom.Call.RejectReason int rejectReason)
+            throws CallStateException {
+        mOwner.hangup(this, rejectReason);
+    }
+
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("[ImsPhoneCall ");
@@ -199,7 +204,9 @@
             }
 
             if (hasOnlyDisconnectedConnections) {
-                mState = State.DISCONNECTED;
+                synchronized(this) {
+                    mState = State.DISCONNECTED;
+                }
                 if (VDBG) {
                     Rlog.v(LOG_TAG, "connectionDisconnected : " + mCallContext + " state = " +
                             mState);
@@ -235,13 +242,17 @@
      * Called when this Call is being hung up locally (eg, user pressed "end")
      */
     @UnsupportedAppUsage
-    void
-    onHangupLocal() {
+    @VisibleForTesting
+    public void onHangupLocal() {
         for (int i = 0, s = mConnections.size(); i < s; i++) {
             ImsPhoneConnection cn = (ImsPhoneConnection)mConnections.get(i);
             cn.onHangupLocal();
         }
-        mState = State.DISCONNECTING;
+        synchronized(this) {
+            if (mState.isAlive()) {
+                mState = State.DISCONNECTING;
+            }
+        }
         if (VDBG) {
             Rlog.v(LOG_TAG, "onHangupLocal : " + mCallContext + " state = " + mState);
         }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 0070e3d..7035840 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -19,7 +19,7 @@
 import static com.android.internal.telephony.Phone.CS_FALLBACK;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -32,7 +32,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkStats;
-import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
@@ -42,18 +41,15 @@
 import android.os.RegistrantList;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
-import com.android.ims.internal.ConferenceParticipant;
+import android.sysprop.TelephonyProperties;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
-import android.telephony.AccessNetworkConstants;
 import android.telephony.CallQuality;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -65,7 +61,6 @@
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.telephony.ims.ImsSuppServiceNotification;
 import android.telephony.ims.ProvisioningManager;
-import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -74,6 +69,7 @@
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseIntArray;
 
 import com.android.ims.FeatureConnector;
 import com.android.ims.ImsCall;
@@ -84,6 +80,7 @@
 import com.android.ims.ImsManager;
 import com.android.ims.ImsMultiEndpoint;
 import com.android.ims.ImsUtInterface;
+import com.android.ims.internal.ConferenceParticipant;
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsVideoCallProvider;
 import com.android.ims.internal.ImsVideoCallProviderWrapper;
@@ -91,6 +88,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallFailCause;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CallTracker;
 import com.android.internal.telephony.CommandException;
@@ -99,20 +97,20 @@
 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.emergency.EmergencyNumberTracker;
 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;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.net.NetworkStatsService;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -218,6 +216,7 @@
                     }
                 }
                 conn.setAllowAddCallDuringVideoCall(mAllowAddCallDuringVideoCall);
+                conn.setAllowHoldingVideoCall(mAllowHoldingVideoCall);
                 addConnection(conn);
 
                 setVideoCallProvider(conn, imsCall);
@@ -319,6 +318,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 +442,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}.
@@ -468,6 +469,12 @@
     private boolean mAllowAddCallDuringVideoCall = true;
 
     /**
+     * Carrier configuration option which determines whether holding a video call
+     * should be allowed.
+     */
+    private boolean mAllowHoldingVideoCall = true;
+
+    /**
      * Carrier configuration option which determines whether to notify the connection if a handover
      * to wifi fails.
      */
@@ -480,6 +487,237 @@
     private boolean mSupportDowngradeVtToAudio = false;
 
     /**
+     * Stores the mapping of {@code ImsReasonInfo#CODE_*} to {@code CallFailCause#*}
+     */
+    private static final SparseIntArray PRECISE_CAUSE_MAP = new SparseIntArray();
+    static {
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT,
+                CallFailCause.LOCAL_ILLEGAL_ARGUMENT);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_ILLEGAL_STATE,
+                CallFailCause.LOCAL_ILLEGAL_STATE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR,
+                CallFailCause.LOCAL_INTERNAL_ERROR);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN,
+                CallFailCause.LOCAL_IMS_SERVICE_DOWN);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL,
+                CallFailCause.LOCAL_NO_PENDING_CALL);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE,
+                CallFailCause.NORMAL_CLEARING);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_POWER_OFF,
+                CallFailCause.LOCAL_POWER_OFF);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_LOW_BATTERY,
+                CallFailCause.LOCAL_LOW_BATTERY);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_SERVICE,
+                CallFailCause.LOCAL_NETWORK_NO_SERVICE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_LTE_COVERAGE,
+                CallFailCause.LOCAL_NETWORK_NO_LTE_COVERAGE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_ROAMING,
+                CallFailCause.LOCAL_NETWORK_ROAMING);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_IP_CHANGED,
+                CallFailCause.LOCAL_NETWORK_IP_CHANGED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE,
+                CallFailCause.LOCAL_SERVICE_UNAVAILABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
+                CallFailCause.LOCAL_NOT_REGISTERED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_EXCEEDED,
+                CallFailCause.LOCAL_MAX_CALL_EXCEEDED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_DECLINE,
+                CallFailCause.LOCAL_CALL_DECLINE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_VCC_ON_PROGRESSING,
+                CallFailCause.LOCAL_CALL_VCC_ON_PROGRESSING);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED,
+                CallFailCause.LOCAL_CALL_RESOURCE_RESERVATION_FAILED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED,
+                CallFailCause.LOCAL_CALL_CS_RETRY_REQUIRED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED,
+                CallFailCause.LOCAL_CALL_VOLTE_RETRY_REQUIRED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_TERMINATED,
+                CallFailCause.LOCAL_CALL_TERMINATED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
+                CallFailCause.LOCAL_HO_NOT_FEASIBLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_TIMEOUT_1XX_WAITING,
+                CallFailCause.TIMEOUT_1XX_WAITING);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_TIMEOUT_NO_ANSWER,
+                CallFailCause.TIMEOUT_NO_ANSWER);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE,
+                CallFailCause.TIMEOUT_NO_ANSWER_CALL_UPDATE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_FDN_BLOCKED,
+                CallFailCause.FDN_BLOCKED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_REDIRECTED,
+                CallFailCause.SIP_REDIRECTED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_BAD_REQUEST,
+                CallFailCause.SIP_BAD_REQUEST);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_FORBIDDEN,
+                CallFailCause.SIP_FORBIDDEN);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_FOUND,
+                CallFailCause.SIP_NOT_FOUND);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_SUPPORTED,
+                CallFailCause.SIP_NOT_SUPPORTED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_REQUEST_TIMEOUT,
+                CallFailCause.SIP_REQUEST_TIMEOUT);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_TEMPRARILY_UNAVAILABLE,
+                CallFailCause.SIP_TEMPRARILY_UNAVAILABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_BAD_ADDRESS,
+                CallFailCause.SIP_BAD_ADDRESS);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_BUSY,
+                CallFailCause.SIP_BUSY);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_REQUEST_CANCELLED,
+                CallFailCause.SIP_REQUEST_CANCELLED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_ACCEPTABLE,
+                CallFailCause.SIP_NOT_ACCEPTABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_REACHABLE,
+                CallFailCause.SIP_NOT_REACHABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_CLIENT_ERROR,
+                CallFailCause.SIP_CLIENT_ERROR);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_TRANSACTION_DOES_NOT_EXIST,
+                CallFailCause.SIP_TRANSACTION_DOES_NOT_EXIST);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVER_INTERNAL_ERROR,
+                CallFailCause.SIP_SERVER_INTERNAL_ERROR);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVICE_UNAVAILABLE,
+                CallFailCause.SIP_SERVICE_UNAVAILABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVER_TIMEOUT,
+                CallFailCause.SIP_SERVER_TIMEOUT);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVER_ERROR,
+                CallFailCause.SIP_SERVER_ERROR);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_USER_REJECTED,
+                CallFailCause.SIP_USER_REJECTED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_GLOBAL_ERROR,
+                CallFailCause.SIP_GLOBAL_ERROR);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EMERGENCY_TEMP_FAILURE,
+                CallFailCause.IMS_EMERGENCY_TEMP_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EMERGENCY_PERM_FAILURE,
+                CallFailCause.IMS_EMERGENCY_PERM_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_INIT_FAILED,
+                CallFailCause.MEDIA_INIT_FAILED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_NO_DATA,
+                CallFailCause.MEDIA_NO_DATA);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_NOT_ACCEPTABLE,
+                CallFailCause.MEDIA_NOT_ACCEPTABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_UNSPECIFIED,
+                CallFailCause.MEDIA_UNSPECIFIED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_TERMINATED,
+                CallFailCause.USER_TERMINATED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_NOANSWER,
+                CallFailCause.USER_NOANSWER);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_IGNORE,
+                CallFailCause.USER_IGNORE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_DECLINE,
+                CallFailCause.USER_DECLINE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOW_BATTERY,
+                CallFailCause.LOW_BATTERY);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_BLACKLISTED_CALL_ID,
+                CallFailCause.BLACKLISTED_CALL_ID);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE,
+                CallFailCause.USER_TERMINATED_BY_REMOTE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_NOT_SUPPORTED,
+                CallFailCause.UT_NOT_SUPPORTED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE,
+                CallFailCause.UT_SERVICE_UNAVAILABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_OPERATION_NOT_ALLOWED,
+                CallFailCause.UT_OPERATION_NOT_ALLOWED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_NETWORK_ERROR,
+                CallFailCause.UT_NETWORK_ERROR);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH,
+                CallFailCause.UT_CB_PASSWORD_MISMATCH);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED,
+                CallFailCause.ECBM_NOT_SUPPORTED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED,
+                CallFailCause.MULTIENDPOINT_NOT_SUPPORTED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE,
+                CallFailCause.CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_ANSWERED_ELSEWHERE,
+                CallFailCause.ANSWERED_ELSEWHERE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_CALL_PULL_OUT_OF_SYNC,
+                CallFailCause.CALL_PULL_OUT_OF_SYNC);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_CALL_END_CAUSE_CALL_PULL,
+                CallFailCause.CALL_PULLED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SUPP_SVC_FAILED,
+                CallFailCause.SUPP_SVC_FAILED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SUPP_SVC_CANCELLED,
+                CallFailCause.SUPP_SVC_CANCELLED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SUPP_SVC_REINVITE_COLLISION,
+                CallFailCause.SUPP_SVC_REINVITE_COLLISION);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_IWLAN_DPD_FAILURE,
+                CallFailCause.IWLAN_DPD_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EPDG_TUNNEL_ESTABLISH_FAILURE,
+                CallFailCause.EPDG_TUNNEL_ESTABLISH_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EPDG_TUNNEL_REKEY_FAILURE,
+                CallFailCause.EPDG_TUNNEL_REKEY_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EPDG_TUNNEL_LOST_CONNECTION,
+                CallFailCause.EPDG_TUNNEL_LOST_CONNECTION);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED,
+                CallFailCause.MAXIMUM_NUMBER_OF_CALLS_REACHED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_REMOTE_CALL_DECLINE,
+                CallFailCause.REMOTE_CALL_DECLINE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_DATA_LIMIT_REACHED,
+                CallFailCause.DATA_LIMIT_REACHED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_DATA_DISABLED,
+                CallFailCause.DATA_DISABLED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_WIFI_LOST,
+                CallFailCause.WIFI_LOST);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_OFF,
+                CallFailCause.RADIO_OFF);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NO_VALID_SIM,
+                CallFailCause.NO_VALID_SIM);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_INTERNAL_ERROR,
+                CallFailCause.RADIO_INTERNAL_ERROR);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NETWORK_RESP_TIMEOUT,
+                CallFailCause.NETWORK_RESP_TIMEOUT);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NETWORK_REJECT,
+                CallFailCause.NETWORK_REJECT);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_ACCESS_FAILURE,
+                CallFailCause.RADIO_ACCESS_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_LINK_FAILURE,
+                CallFailCause.RADIO_LINK_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_LINK_LOST,
+                CallFailCause.RADIO_LINK_LOST);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_UPLINK_FAILURE,
+                CallFailCause.RADIO_UPLINK_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_SETUP_FAILURE,
+                CallFailCause.RADIO_SETUP_FAILURE);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_RELEASE_NORMAL,
+                CallFailCause.RADIO_RELEASE_NORMAL);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_RELEASE_ABNORMAL,
+                CallFailCause.RADIO_RELEASE_ABNORMAL);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_ACCESS_CLASS_BLOCKED,
+                CallFailCause.ACCESS_CLASS_BLOCKED);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NETWORK_DETACH,
+                CallFailCause.NETWORK_DETACH);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UNOBTAINABLE_NUMBER,
+                CallFailCause.UNOBTAINABLE_NUMBER);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_1,
+                CallFailCause.OEM_CAUSE_1);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_2,
+                CallFailCause.OEM_CAUSE_2);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_3,
+                CallFailCause.OEM_CAUSE_3);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_4,
+                CallFailCause.OEM_CAUSE_4);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_5,
+                CallFailCause.OEM_CAUSE_5);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_6,
+                CallFailCause.OEM_CAUSE_6);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_7,
+                CallFailCause.OEM_CAUSE_7);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_8,
+                CallFailCause.OEM_CAUSE_8);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_9,
+                CallFailCause.OEM_CAUSE_9);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_10,
+                CallFailCause.OEM_CAUSE_10);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_11,
+                CallFailCause.OEM_CAUSE_11);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_12,
+                CallFailCause.OEM_CAUSE_12);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_13,
+                CallFailCause.OEM_CAUSE_13);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_14,
+                CallFailCause.OEM_CAUSE_14);
+        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_15,
+                CallFailCause.OEM_CAUSE_15);
+    }
+
+    /**
      * Carrier configuration option which determines whether the carrier wants to inform the user
      * when a video call is handed over from WIFI to LTE.
      * See {@link CarrierConfigManager#KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL} for more
@@ -586,15 +824,10 @@
         mVtDataUsageUidSnapshot = new NetworkStats(currentTime, 1);
 
         // Allow the executor to be specified for testing.
-        mImsManagerConnector = new FeatureConnector<ImsManager>(
+        mImsManagerConnector = new FeatureConnector<>(
                 phone.getContext(), phone.getPhoneId(),
                 new FeatureConnector.Listener<ImsManager>() {
                     @Override
-                    public boolean isSupported() {
-                        return ImsManager.isImsSupportedOnDevice(phone.getContext());
-                    }
-
-                    @Override
                     public ImsManager getFeatureManager() {
                         return ImsManager.getInstance(phone.getContext(), phone.getPhoneId());
                     }
@@ -660,7 +893,7 @@
         log("startListeningForCalls");
         mOperationLocalLog.log("startListeningForCalls - Connecting to ImsService");
         mImsManager.open(mMmTelFeatureListener);
-        mImsManager.addRegistrationCallback(mImsRegistrationCallback);
+        mImsManager.addRegistrationCallback(mPhone.getImsMmTelRegistrationCallback());
         mImsManager.addCapabilitiesCallback(mImsCapabilityCallback);
 
         mImsManager.setConfigListener(mImsConfigListener);
@@ -782,6 +1015,96 @@
         }
     }
 
+    private boolean prepareForDialing(ImsPhone.ImsDialArgs dialArgs) throws CallStateException {
+        boolean holdBeforeDial = false;
+        // note that this triggers call state changed notif
+        clearDisconnected();
+        if (mImsManager == null) {
+            throw new CallStateException("service not available");
+        }
+        // See if there are any issues which preclude placing a call; throw a CallStateException
+        // if there is.
+        checkForDialIssues();
+        int videoState = dialArgs.videoState;
+        if (!canAddVideoCallDuringImsAudioCall(videoState)) {
+            throw new CallStateException("cannot dial in current state");
+        }
+
+        // The new call must be assigned to the foreground call.
+        // That call must be idle, so place anything that's
+        // there on hold
+        if (mForegroundCall.getState() == ImsPhoneCall.State.ACTIVE) {
+            if (mBackgroundCall.getState() != ImsPhoneCall.State.IDLE) {
+                //we should have failed in checkForDialIssues above before we get here
+                throw new CallStateException(CallStateException.ERROR_TOO_MANY_CALLS,
+                        "Already too many ongoing calls.");
+            }
+            // foreground call is empty for the newly dialed connection
+            holdBeforeDial = true;
+            mPendingCallVideoState = videoState;
+            mPendingIntentExtras = dialArgs.intentExtras;
+            holdActiveCallForPendingMo();
+        }
+
+        ImsPhoneCall.State fgState = ImsPhoneCall.State.IDLE;
+        ImsPhoneCall.State bgState = ImsPhoneCall.State.IDLE;
+
+        synchronized (mSyncHold) {
+            if (holdBeforeDial) {
+                fgState = mForegroundCall.getState();
+                bgState = mBackgroundCall.getState();
+                //holding foreground call failed
+                if (fgState == ImsPhoneCall.State.ACTIVE) {
+                    throw new CallStateException("cannot dial in current state");
+                }
+                //holding foreground call succeeded
+                if (bgState == ImsPhoneCall.State.HOLDING) {
+                    holdBeforeDial = false;
+                }
+            }
+        }
+        return holdBeforeDial;
+    }
+
+    public Connection startConference(String[] participantsToDial, ImsPhone.ImsDialArgs dialArgs)
+            throws CallStateException {
+
+        int clirMode = dialArgs.clirMode;
+        int videoState = dialArgs.videoState;
+
+        if (DBG) log("dial clirMode=" + clirMode);
+        boolean holdBeforeDial = prepareForDialing(dialArgs);
+
+        mClirMode = clirMode;
+        ImsPhoneConnection pendingConnection;
+        synchronized (mSyncHold) {
+            mLastDialArgs = dialArgs;
+            pendingConnection = new ImsPhoneConnection(mPhone,
+                    participantsToDial, this, mForegroundCall,
+                    false);
+            // Don't rely on the mPendingMO in this method; if the modem calls back through
+            // onCallProgressing, we'll end up nulling out mPendingMO, which means that
+            // TelephonyConnectionService would treat this call as an MMI code, which it is not,
+            // which would mean that the MMI code dialog would crash.
+            mPendingMO = pendingConnection;
+            pendingConnection.setVideoState(videoState);
+            if (dialArgs.rttTextStream != null) {
+                log("startConference: setting RTT stream on mPendingMO");
+                pendingConnection.setCurrentRttTextStream(dialArgs.rttTextStream);
+            }
+        }
+        addConnection(pendingConnection);
+
+        if (!holdBeforeDial) {
+            dialInternal(pendingConnection, clirMode, videoState, dialArgs.intentExtras);
+        }
+
+        updatePhoneState();
+        mPhone.notifyPreciseCallStateChanged();
+
+        return pendingConnection;
+    }
+
     @UnsupportedAppUsage
     public Connection dial(String dialString, int videoState, Bundle intentExtras) throws
             CallStateException {
@@ -817,16 +1140,8 @@
             dialString = convertNumberIfNecessary(mPhone, dialString);
         }
 
-        // note that this triggers call state changed notif
-        clearDisconnected();
-
-        if (mImsManager == null) {
-            throw new CallStateException("service not available");
-        }
-
-        // See if there are any issues which preclude placing a call; throw a CallStateException
-        // if there is.
-        checkForDialIssues();
+        mClirMode = clirMode;
+        boolean holdBeforeDial = prepareForDialing(dialArgs);
 
         if (isPhoneInEcmMode && isEmergencyNumber) {
             handleEcmTimer(ImsPhone.CANCEL_ECM_TIMER);
@@ -840,46 +1155,10 @@
             videoState = VideoProfile.STATE_AUDIO_ONLY;
         }
 
-        boolean holdBeforeDial = false;
-
-        // The new call must be assigned to the foreground call.
-        // That call must be idle, so place anything that's
-        // there on hold
-        if (mForegroundCall.getState() == ImsPhoneCall.State.ACTIVE) {
-            if (mBackgroundCall.getState() != ImsPhoneCall.State.IDLE) {
-                //we should have failed in checkForDialIssues above before we get here
-                throw new CallStateException(CallStateException.ERROR_TOO_MANY_CALLS,
-                        "Already too many ongoing calls.");
-            }
-            // foreground call is empty for the newly dialed connection
-            holdBeforeDial = true;
-            // Cache the video state for pending MO call.
-            mPendingCallVideoState = videoState;
-            mPendingIntentExtras = dialArgs.intentExtras;
-            holdActiveCallForPendingMo();
-        }
-
-        ImsPhoneCall.State fgState = ImsPhoneCall.State.IDLE;
-        ImsPhoneCall.State bgState = ImsPhoneCall.State.IDLE;
-
-        mClirMode = clirMode;
+        // Cache the video state for pending MO call.
+        mPendingCallVideoState = videoState;
 
         synchronized (mSyncHold) {
-            if (holdBeforeDial) {
-                fgState = mForegroundCall.getState();
-                bgState = mBackgroundCall.getState();
-
-                //holding foreground call failed
-                if (fgState == ImsPhoneCall.State.ACTIVE) {
-                    throw new CallStateException("cannot dial in current state");
-                }
-
-                //holding foreground call succeeded
-                if (bgState == ImsPhoneCall.State.HOLDING) {
-                    holdBeforeDial = false;
-                }
-            }
-
             mLastDialString = dialString;
             mLastDialArgs = dialArgs;
             mPendingMO = new ImsPhoneConnection(mPhone,
@@ -912,6 +1191,7 @@
                 mPhone.setOnEcbModeExitResponse(this, EVENT_EXIT_ECM_RESPONSE_CDMA, null);
                 pendingCallClirMode = clirMode;
                 mPendingCallVideoState = videoState;
+                mPendingIntentExtras = dialArgs.intentExtras;
                 pendingCallInEcm = true;
             }
         }
@@ -1012,6 +1292,9 @@
         mAllowAddCallDuringVideoCall =
                 carrierConfig.getBoolean(
                         CarrierConfigManager.KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL);
+        mAllowHoldingVideoCall =
+                carrierConfig.getBoolean(
+                        CarrierConfigManager.KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL);
         mNotifyVtHandoverToWifiFail = carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL);
         mSupportDowngradeVtToAudio = carrierConfig.getBoolean(
@@ -1086,8 +1369,9 @@
             return;
         }
 
-        if (conn.getAddress()== null || conn.getAddress().length() == 0
-                || conn.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {
+        if (!conn.isAdhocConference() &&
+                (conn.getAddress()== null || conn.getAddress().length() == 0
+                || conn.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0)) {
             // Phone number is invalid
             conn.setDisconnectCause(DisconnectCause.INVALID_NUMBER);
             sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO);
@@ -1106,6 +1390,9 @@
         try {
             String[] callees = new String[] { conn.getAddress() };
             ImsCallProfile profile = mImsManager.createCallProfile(serviceType, callType);
+            if (conn.isAdhocConference()) {
+                profile.setCallExtraBoolean(ImsCallProfile.EXTRA_CONFERENCE, true);
+            }
             profile.setCallExtraInt(ImsCallProfile.EXTRA_OIR, clirMode);
 
             if (isEmergencyCall) {
@@ -1145,7 +1432,9 @@
                 // being sent to the lower layers/to the network.
             }
 
-            ImsCall imsCall = mImsManager.makeCall(profile, callees, mImsCallListener);
+            ImsCall imsCall = mImsManager.makeCall(profile,
+                    conn.isAdhocConference() ? conn.getParticipantsToDial() : callees,
+                    mImsCallListener);
             conn.setImsCall(imsCall);
 
             mMetrics.writeOnImsCallStart(mPhone.getPhoneId(),
@@ -1153,6 +1442,7 @@
 
             setVideoCallProvider(conn, imsCall);
             conn.setAllowAddCallDuringVideoCall(mAllowAddCallDuringVideoCall);
+            conn.setAllowHoldingVideoCall(mAllowHoldingVideoCall);
         } catch (ImsException e) {
             loge("dialInternal : " + e);
             mOperationLocalLog.log("dialInternal exception: " + e);
@@ -1344,7 +1634,7 @@
     /**
      * Unhold the currently held call.
      */
-    void unholdHeldCall() throws CallStateException {
+    public void unholdHeldCall() throws CallStateException {
         ImsCall imsCall = mBackgroundCall.getImsCall();
         if (mHoldSwitchingState == HoldSwapState.PENDING_SINGLE_CALL_UNHOLD
                 || mHoldSwitchingState == HoldSwapState.SWAPPING_ACTIVE_AND_HELD) {
@@ -1558,15 +1848,33 @@
             && !mForegroundCall.isFull();
     }
 
+    private boolean canAddVideoCallDuringImsAudioCall(int videoState) {
+        if (mAllowHoldingVideoCall) {
+            return true;
+        }
+
+        ImsCall call = mForegroundCall.getImsCall();
+        if (call == null) {
+            call = mBackgroundCall.getImsCall();
+        }
+
+        boolean isImsAudioCallActiveOrHolding = (mForegroundCall.getState() == Call.State.ACTIVE ||
+               mBackgroundCall.getState() == Call.State.HOLDING) && call != null &&
+               !call.isVideoCall();
+
+        /* return TRUE if there doesn't exist ims audio call in either active
+           or hold states */
+        return !isImsAudioCallActiveOrHolding || !VideoProfile.isVideo(videoState);
+    }
+
     /**
      * Determines if there are issues which would preclude dialing an outgoing call.  Throws a
      * {@link CallStateException} if there is an issue.
      * @throws CallStateException
      */
     public void checkForDialIssues() throws CallStateException {
-        String disableCall = SystemProperties.get(
-                TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
-        if (disableCall.equals("true")) {
+        boolean disableCall = TelephonyProperties.disable_call().orElse(false);
+        if (disableCall) {
             throw new CallStateException(CallStateException.ERROR_CALLING_DISABLED,
                     "ro.telephony.disable-call has been used to disable calling.");
         }
@@ -1781,7 +2089,12 @@
     //***** Called from ImsPhoneCall
 
     public void hangup (ImsPhoneCall call) throws CallStateException {
-        if (DBG) log("hangup call");
+        hangup(call, android.telecom.Call.REJECT_REASON_DECLINED);
+    }
+
+    public void hangup (ImsPhoneCall call, @android.telecom.Call.RejectReason int rejectReason)
+            throws CallStateException {
+        if (DBG) log("hangup call - reason=" + rejectReason);
 
         if (call.getConnections().size() == 0) {
             throw new CallStateException("no connections");
@@ -1818,7 +2131,11 @@
         try {
             if (imsCall != null) {
                 if (rejectCall) {
-                    imsCall.reject(ImsReasonInfo.CODE_USER_DECLINE);
+                    if (rejectReason == android.telecom.Call.REJECT_REASON_UNWANTED) {
+                        imsCall.reject(ImsReasonInfo.CODE_SIP_USER_MARKED_UNWANTED);
+                    } else {
+                        imsCall.reject(ImsReasonInfo.CODE_USER_DECLINE);
+                    }
                     mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
                             ImsCommand.IMS_CMD_REJECT);
                 } else {
@@ -2238,6 +2555,11 @@
         return cause;
     }
 
+    private int getPreciseDisconnectCauseFromReasonInfo(ImsReasonInfo reasonInfo) {
+        return PRECISE_CAUSE_MAP.get(maybeRemapReasonCode(reasonInfo),
+                CallFailCause.ERROR_UNSPECIFIED);
+    }
+
     /**
      * @return true if the phone is in Emergency Callback mode, otherwise false
      */
@@ -2436,9 +2758,12 @@
             }
 
             String callId = imsCall.getSession().getCallId();
+            EmergencyNumberTracker emergencyNumberTracker = conn.getEmergencyNumberTracker();
             mMetrics.writeOnImsCallTerminated(mPhone.getPhoneId(), imsCall.getCallSession(),
                     reasonInfo, mCallQualityMetrics.get(callId), conn.getEmergencyNumberInfo(),
-                    getNetworkCountryIso());
+                    getNetworkCountryIso(), emergencyNumberTracker != null
+                    ? emergencyNumberTracker.getEmergencyNumberDbVersion()
+                    : TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION);
             // Remove info for the callId from the current calls and add it to the history
             CallQualityMetrics lastCallMetrics = mCallQualityMetrics.remove(callId);
             if (lastCallMetrics != null) {
@@ -2447,17 +2772,25 @@
             pruneCallQualityMetricsHistory();
             mPhone.notifyImsReason(reasonInfo);
 
+            if (conn != null) {
+                conn.setPreciseDisconnectCause(getPreciseDisconnectCauseFromReasonInfo(reasonInfo));
+            }
+
             if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL
                     && mAutoRetryFailedWifiEmergencyCall) {
                 Pair<ImsCall, ImsReasonInfo> callInfo = new Pair<>(imsCall, reasonInfo);
-                mPhone.getDefaultPhone().getServiceStateTracker().registerForNetworkAttached(
-                        ImsPhoneCallTracker.this, EVENT_REDIAL_WIFI_E911_CALL, callInfo);
+                mPhone.getDefaultPhone().mCi.registerForOn(ImsPhoneCallTracker.this,
+                        EVENT_REDIAL_WIFI_E911_CALL, callInfo);
                 sendMessageDelayed(obtainMessage(EVENT_REDIAL_WIFI_E911_TIMEOUT, callInfo),
                         TIMEOUT_REDIAL_WIFI_E911_MS);
                 final ConnectivityManager mgr = (ConnectivityManager) mPhone.getContext()
                         .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);
             }
@@ -2640,7 +2973,7 @@
                     mHoldSwitchingState = HoldSwapState.INACTIVE;
                 }
                 ImsPhoneConnection conn = findConnection(imsCall);
-                if (conn != null) {
+                if (conn != null && conn.getState() != ImsPhoneCall.State.DISCONNECTED) {
                     conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_HOLD_FAILED, null);
                 }
                 mPhone.notifySuppServiceFailed(Phone.SuppService.HOLD);
@@ -2793,8 +3126,8 @@
             }
             foregroundImsPhoneCall.merge(peerImsPhoneCall, ImsPhoneCall.State.ACTIVE);
 
+            final ImsPhoneConnection conn = findConnection(call);
             try {
-                final ImsPhoneConnection conn = findConnection(call);
                 log("onCallMerged: ImsPhoneConnection=" + conn);
                 log("onCallMerged: CurrentVideoProvider=" + conn.getVideoProvider());
                 setVideoCallProvider(conn, call);
@@ -2822,6 +3155,11 @@
                 // Reset the flag.
                 call.resetIsMergeRequestedByConf(false);
             }
+
+            // Notify completion of merge
+            if (conn != null) {
+                conn.handleMergeComplete();
+            }
             logState();
         }
 
@@ -3080,8 +3418,7 @@
         @Override
         public void onCallQualityChanged(ImsCall imsCall, CallQuality callQuality) {
             // convert ServiceState.radioTech to TelephonyManager.NetworkType constant
-            mPhone.onCallQualityChanged(callQuality,
-                    ServiceState.rilRadioTechnologyToNetworkType(imsCall.getRadioTechnology()));
+            mPhone.onCallQualityChanged(callQuality, imsCall.getNetworkType());
             String callId = imsCall.getSession().getCallId();
             CallQualityMetrics cqm = mCallQualityMetrics.get(callId);
             if (cqm == null) {
@@ -3157,58 +3494,6 @@
         }
     };
 
-    private final RegistrationManager.RegistrationCallback mImsRegistrationCallback =
-            new RegistrationManager.RegistrationCallback() {
-
-                @Override
-                public void onRegistered(int imsRadioTech) {
-                    if (DBG) {
-                        log("onImsConnected imsRadioTech="
-                                + AccessNetworkConstants.transportTypeToString(imsRadioTech));
-                    }
-                    mRegLocalLog.log("onImsConnected imsRadioTech="
-                            + AccessNetworkConstants.transportTypeToString(imsRadioTech));
-                    mPhone.setServiceState(ServiceState.STATE_IN_SERVICE);
-                    mPhone.setImsRegistrationState(
-                            RegistrationManager.REGISTRATION_STATE_REGISTERED);
-                    mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
-                            ImsConnectionState.State.CONNECTED, null);
-                }
-
-                @Override
-                public void onRegistering(int imsRadioTech) {
-                    if (DBG) {
-                        log("onImsProgressing imsRadioTech="
-                                + AccessNetworkConstants.transportTypeToString(imsRadioTech));
-                    }
-                    mRegLocalLog.log("onImsProgressing imsRadioTech="
-                            + AccessNetworkConstants.transportTypeToString(imsRadioTech));
-                    mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
-                    mPhone.setImsRegistrationState(
-                            RegistrationManager.REGISTRATION_STATE_REGISTERING);
-                    mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
-                            ImsConnectionState.State.PROGRESSING, null);
-                }
-
-                @Override
-                public void onUnregistered(ImsReasonInfo imsReasonInfo) {
-                    if (DBG) log("onImsDisconnected imsReasonInfo=" + imsReasonInfo);
-                    mRegLocalLog.log("onImsDisconnected imsRadioTech=" + imsReasonInfo);
-                    mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
-                    mPhone.setImsRegistrationState(
-                            RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
-                    mPhone.processDisconnectReason(imsReasonInfo);
-                    mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
-                            ImsConnectionState.State.DISCONNECTED, imsReasonInfo);
-                }
-
-                @Override
-                public void onSubscriberAssociatedUriChanged(Uri[] uris) {
-                    if (DBG) log("registrationAssociatedUriChanged");
-                    mPhone.setCurrentSubscriberUris(uris);
-                }
-            };
-
     private final ImsMmTelManager.CapabilityCallback mImsCapabilityCallback =
             new ImsMmTelManager.CapabilityCallback() {
                 @Override
@@ -3246,6 +3531,14 @@
         @Override
         public void onProvisioningIntChanged(int item, int value) {
             sendConfigChangedIntent(item, Integer.toString(value));
+            if ((mImsManager != null)
+                    && (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED
+                    || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED
+                    || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED)) {
+                // Update Ims Service state to make sure updated provisioning values take effect
+                // immediately.
+                mImsManager.updateImsServiceConfig(true);
+            }
         }
 
         @Override
@@ -3285,6 +3578,12 @@
         }
 
         processCallStateChange(imsCall, ImsPhoneCall.State.DISCONNECTED, cause);
+
+        if (conn != null) {
+            conn.setPreciseDisconnectCause(
+                    getPreciseDisconnectCauseFromReasonInfo(reasonInfo));
+        }
+
         mPhone.notifyImsReason(reasonInfo);
     }
 
@@ -3487,8 +3786,7 @@
                 Pair<ImsCall, ImsReasonInfo> callInfo =
                         (Pair<ImsCall, ImsReasonInfo>) ((AsyncResult) msg.obj).userObj;
                 removeMessages(EVENT_REDIAL_WIFI_E911_TIMEOUT);
-                mPhone.getDefaultPhone().getServiceStateTracker()
-                        .unregisterForNetworkAttached(this);
+                mPhone.getDefaultPhone().mCi.unregisterForOn(this);
                 ImsPhoneConnection oldConnection = findConnection(callInfo.first);
                 if (oldConnection == null) {
                     sendCallStartFailedDisconnect(callInfo.first, callInfo.second);
@@ -3500,6 +3798,15 @@
                     Connection newConnection =
                             mPhone.getDefaultPhone().dial(mLastDialString, mLastDialArgs);
                     oldConnection.onOriginalConnectionReplaced(newConnection);
+
+                    final ImsCall imsCall = mForegroundCall.getImsCall();
+                    final ImsCallProfile callProfile = imsCall.getCallProfile();
+                    /* update EXTRA_EMERGENCY_CALL for clients to infer
+                       from this extra that the call is emergency call */
+                    callProfile.setCallExtraBoolean(
+                            ImsCallProfile.EXTRA_EMERGENCY_CALL, true);
+                    ImsPhoneConnection conn = findConnection(imsCall);
+                    conn.updateExtras(imsCall);
                 } catch (CallStateException e) {
                     sendCallStartFailedDisconnect(callInfo.first, callInfo.second);
                 }
@@ -3507,12 +3814,35 @@
             }
             case EVENT_REDIAL_WIFI_E911_TIMEOUT: {
                 Pair<ImsCall, ImsReasonInfo> callInfo = (Pair<ImsCall, ImsReasonInfo>) msg.obj;
-                mPhone.getDefaultPhone().getServiceStateTracker()
-                        .unregisterForNetworkAttached(this);
+                mPhone.getDefaultPhone().mCi.unregisterForOn(this);
                 removeMessages(EVENT_REDIAL_WIFI_E911_CALL);
                 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;
+            }
         }
     }
 
@@ -3666,10 +3996,6 @@
         pw.println(" mCallQualityMetrics=" + mCallQualityMetrics);
         pw.println(" mCallQualityMetricsHistory=" + mCallQualityMetricsHistory);
         pw.println(" mIsConferenceEventPackageHandlingEnabled=" + mIsConferenceEventPackageEnabled);
-        pw.println(" Registration Log:");
-        pw.increaseIndent();
-        mRegLocalLog.dump(pw);
-        pw.decreaseIndent();
         pw.println(" Event Log:");
         pw.increaseIndent();
         mOperationLocalLog.dump(pw);
@@ -4170,8 +4496,7 @@
         boolean tmpIsVideoCallEnabled = isVideoCallEnabled();
         mMmTelCapabilities = new MmTelFeature.MmTelCapabilities();
         mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
-        mPhone.setImsRegistrationState(
-                RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
+        mPhone.resetImsRegistrationState();
         mPhone.processDisconnectReason(new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN,
                 ImsReasonInfo.CODE_UNSPECIFIED));
         boolean isVideoEnabled = isVideoCallEnabled();
@@ -4207,10 +4532,8 @@
                 .getSystemService(Context.CONNECTIVITY_SERVICE);
         if (cm != null) {
             Rlog.i(LOG_TAG, "registerForConnectivityChanges");
-            NetworkCapabilities capabilities = new NetworkCapabilities();
-            capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
             NetworkRequest.Builder builder = new NetworkRequest.Builder();
-            builder.setCapabilities(capabilities);
+            builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
             cm.registerNetworkCallback(builder.build(), mNetworkCallback);
             mIsMonitoringConnectivity = true;
         }
@@ -4388,4 +4711,14 @@
     public boolean isConferenceEventPackageEnabled() {
         return mIsConferenceEventPackageEnabled;
     }
+
+    @VisibleForTesting
+    public ImsCall.Listener getImsCallListener() {
+        return mImsCallListener;
+    }
+
+    @VisibleForTesting
+    public ArrayList<ImsPhoneConnection> getConnections() {
+        return mConnections;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
index 0eba486..53cae3f 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.data.DataProfile;
 import android.telephony.emergency.EmergencyNumber;
 
@@ -240,6 +241,10 @@
     }
 
     @Override
+    public void sendCdmaSMSExpectMore(byte[] pdu, Message result) {
+    }
+
+    @Override
     public void sendImsGsmSms (String smscPDU, String pdu,
             int retry, int messageRef, Message response) {
     }
@@ -333,8 +338,7 @@
     }
 
     @Override
-    public void setNetworkSelectionModeManual(
-            String operatorNumeric, Message response) {
+    public void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message response) {
     }
 
     @Override
@@ -635,8 +639,8 @@
     }
 
     @Override
-    public void setSignalStrengthReportingCriteria(int hysteresisMs, int hysteresisDb,
-            int[] thresholdsDbm, int ran, Message result) {
+    public void setSignalStrengthReportingCriteria(
+            SignalThresholdInfo signalThresholdInfo, int ran, Message result) {
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index c7dbf4e..c29f45f 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.imsphone;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.net.Uri;
 import android.os.AsyncResult;
@@ -33,8 +33,8 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.text.TextUtils;
@@ -47,7 +47,9 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.telephony.Rlog;
 
 import java.util.Objects;
 
@@ -132,9 +134,6 @@
      */
     private boolean mIsLocalVideoCapable = true;
 
-    // Store the current audio codec
-    private int mAudioCodec = ImsStreamMediaProfile.AUDIO_QUALITY_NONE;
-
     //***** Event Constants
     private static final int EVENT_DTMF_DONE = 1;
     private static final int EVENT_PAUSE_DONE = 2;
@@ -187,6 +186,7 @@
         mHandler = new MyHandler(mOwner.getLooper());
         mHandlerMessenger = new Messenger(mHandler);
         mImsCall = imsCall;
+        mIsAdhocConference = isMultiparty();
 
         if ((imsCall != null) && (imsCall.getCallProfile() != null)) {
             mAddress = imsCall.getCallProfile().getCallExtra(ImsCallProfile.EXTRA_OI);
@@ -262,6 +262,37 @@
         }
     }
 
+    /** This is an MO conference call, created when dialing */
+    public ImsPhoneConnection(Phone phone, String[] participantsToDial, ImsPhoneCallTracker ct,
+            ImsPhoneCall parent, boolean isEmergency) {
+        super(PhoneConstants.PHONE_TYPE_IMS);
+        createWakeLock(phone.getContext());
+        acquireWakeLock();
+
+        mOwner = ct;
+        mHandler = new MyHandler(mOwner.getLooper());
+        mHandlerMessenger = new Messenger(mHandler);
+
+        mDialString = mAddress = Connection.ADHOC_CONFERENCE_ADDRESS;
+        mParticipantsToDial = participantsToDial;
+        mIsAdhocConference = true;
+
+        mIsIncoming = false;
+        mCnapName = null;
+        mCnapNamePresentation = PhoneConstants.PRESENTATION_ALLOWED;
+        mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED;
+        mCreateTime = System.currentTimeMillis();
+
+        mParent = parent;
+        parent.attachFake(this, ImsPhoneCall.State.DIALING);
+
+        if (phone.getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_use_voip_mode_for_ims)) {
+            setAudioModeIsVoip(true);
+        }
+    }
+
+
     public void dispose() {
     }
 
@@ -1097,6 +1128,20 @@
         }
     }
 
+    /**
+     * Get the corresponding EmergencyNumberTracker associated with the connection.
+     * @return the EmergencyNumberTracker
+     */
+    public EmergencyNumberTracker getEmergencyNumberTracker() {
+        if (mOwner != null) {
+            Phone phone = mOwner.getPhone();
+            if (phone != null) {
+                return phone.getEmergencyNumberTracker();
+            }
+        }
+        return null;
+    }
+
     public boolean hasRttTextStream() {
         return mRttTextStream != null;
     }
@@ -1137,17 +1182,18 @@
      * @param extras The ImsCallProfile extras.
      */
     private void updateImsCallRatFromExtras(Bundle extras) {
-        if (extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE) ||
-                extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT)) {
+        if (extras.containsKey(ImsCallProfile.EXTRA_CALL_NETWORK_TYPE)
+                || extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE)
+                || extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT)) {
 
             ImsCall call = getImsCall();
-            int callTech = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+            int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
             if (call != null) {
-                callTech = call.getRadioTechnology();
+                networkType = call.getNetworkType();
             }
 
-            // Report any changes for call tech change
-            setCallRadioTech(callTech);
+            // Report any changes for network type change
+            setCallRadioTech(ServiceState.networkTypeToRilRadioTechnology(networkType));
         }
     }
 
@@ -1255,6 +1301,8 @@
         sb.append(getTelecomCallId());
         sb.append(" address: ");
         sb.append(Rlog.pii(LOG_TAG, getAddress()));
+        sb.append(" isAdhocConf: ");
+        sb.append(isAdhocConference() ? "Y" : "N");
         sb.append(" ImsCall: ");
         synchronized (this) {
             if (mImsCall == null) {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java
index 9f81a69..8f82328 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java
@@ -16,11 +16,11 @@
 
 package com.android.internal.telephony.imsphone;
 
+import android.content.Context;
+
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneNotifier;
-
-import android.content.Context;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
index 403b535..adea6ef 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
@@ -27,7 +27,7 @@
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_SMS;
 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.AsyncResult;
@@ -35,17 +35,16 @@
 import android.os.Message;
 import android.os.ResultReceiver;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ims.ImsCallForwardInfo;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsSsData;
 import android.telephony.ims.ImsSsInfo;
 import android.telephony.ims.ImsUtListener;
+import android.telephony.ims.stub.ImsUtImplBase;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 
 import com.android.ims.ImsException;
-import com.android.ims.ImsUtInterface;
 import com.android.internal.telephony.CallForwardInfo;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.CommandException;
@@ -53,6 +52,7 @@
 import com.android.internal.telephony.MmiCode;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.uicc.IccRecords;
+import com.android.telephony.Rlog;
 
 import java.util.Arrays;
 import java.util.List;
@@ -468,7 +468,7 @@
         Resources resource = Resources.getSystem();
         if (sc != null) {
             String[] barringMMI = resource.getStringArray(
-                com.android.internal.R.array.config_callBarringMMI);
+                com.android.internal.R.array.config_callBarringMMI_for_ims);
             if (barringMMI != null) {
                 for (String match : barringMMI) {
                     if (sc.equals(match)) return true;
@@ -975,9 +975,9 @@
             } else if (mSc != null && (mSc.equals(SC_BS_MT))) {
                 try {
                     if (isInterrogate()) {
-                        mPhone.mCT.getUtInterface()
-                        .queryCallBarring(ImsUtInterface.CB_BS_MT,
-                                          obtainMessage(EVENT_QUERY_ICB_COMPLETE,this));
+                        mPhone.mCT.getUtInterface().queryCallBarring(
+                                ImsUtImplBase.CALL_BARRING_SPECIFIC_INCOMING_CALLS,
+                                obtainMessage(EVENT_QUERY_ICB_COMPLETE, this));
                     } else {
                         processIcbMmiCodeForUpdate();
                     }
@@ -990,9 +990,9 @@
                 // TODO: Should we route through queryCallBarring() here?
                 try {
                     if (isInterrogate()) {
-                        mPhone.mCT.getUtInterface()
-                        .queryCallBarring(ImsUtInterface.CB_BIC_ACR,
-                                          obtainMessage(EVENT_QUERY_ICB_COMPLETE,this));
+                        mPhone.mCT.getUtInterface().queryCallBarring(
+                                ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING,
+                                obtainMessage(EVENT_QUERY_ICB_COMPLETE, this));
                     } else {
                         if (isActivate()) {
                             callAction = CommandsInterface.CF_ACTION_ENABLE;
@@ -1000,7 +1000,7 @@
                             callAction = CommandsInterface.CF_ACTION_DISABLE;
                         }
                         mPhone.mCT.getUtInterface()
-                                .updateCallBarring(ImsUtInterface.CB_BIC_ACR,
+                                .updateCallBarring(ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING,
                                 callAction,
                                 obtainMessage(EVENT_SET_COMPLETE,this),
                                 null);
@@ -1010,7 +1010,7 @@
                 }
             } else if (mSc != null && mSc.equals(SC_WAIT)) {
                 // sia = basic service group
-                int serviceClass = siToServiceClass(mSib);
+                int serviceClass = siToServiceClass(mSia);
 
                 if (isActivate() || isDeactivate()) {
                     mPhone.setCallWaiting(isActivate(), serviceClass,
@@ -1190,11 +1190,11 @@
         callAction = callBarAction(dialingNumber);
 
         try {
-            mPhone.mCT.getUtInterface()
-            .updateCallBarring(ImsUtInterface.CB_BS_MT,
-                               callAction,
-                               obtainMessage(EVENT_SET_COMPLETE,this),
-                               icbNum);
+            mPhone.mCT.getUtInterface().updateCallBarring(
+                    ImsUtImplBase.CALL_BARRING_SPECIFIC_INCOMING_CALLS,
+                    callAction,
+                    obtainMessage(EVENT_SET_COMPLETE, this),
+                    icbNum);
         } catch (ImsException e) {
             Rlog.d(LOG_TAG, "processIcbMmiCodeForUpdate:Could not get UT handle for updating ICB.");
         }
@@ -1415,9 +1415,7 @@
                 (info.serviceClass & serviceClassMask)
                         == CommandsInterface.SERVICE_CLASS_VOICE) {
             boolean cffEnabled = (info.status == 1);
-            if (mIccRecords != null) {
-                mPhone.setVoiceCallForwardingFlag(1, cffEnabled, info.number);
-            }
+            mPhone.setVoiceCallForwardingFlag(mIccRecords, 1, cffEnabled, info.number);
         }
 
         return TextUtils.replace(template, sources, destinations);
@@ -1448,9 +1446,7 @@
                 sb.append(mContext.getText(com.android.internal.R.string.serviceDisabled));
 
                 // Set unconditional CFF in SIM to false
-                if (mIccRecords != null) {
-                    mPhone.setVoiceCallForwardingFlag(1, false, null);
-                }
+                mPhone.setVoiceCallForwardingFlag(mIccRecords, 1, false, null);
             } else {
 
                 SpannableStringBuilder tb = new SpannableStringBuilder();
@@ -1678,9 +1674,8 @@
         StringBuilder sb = new StringBuilder(getScString());
         sb.append("\n");
 
+        mState = State.FAILED;
         if (ar.exception != null) {
-            mState = State.FAILED;
-
             if (ar.exception instanceof ImsException) {
                 sb.append(getImsErrorMessage(ar));
             } else {
@@ -1693,19 +1688,21 @@
             if (ints.length != 0) {
                 if (ints[0] == 0) {
                     sb.append(mContext.getText(com.android.internal.R.string.serviceDisabled));
+                    mState = State.COMPLETE;
                 } else if (mSc.equals(SC_WAIT)) {
                     // Call Waiting includes additional data in the response.
                     sb.append(createQueryCallWaitingResultMessage(ints[1]));
+                    mState = State.COMPLETE;
                 } else if (ints[0] == 1) {
                     // for all other services, treat it as a boolean
                     sb.append(mContext.getText(com.android.internal.R.string.serviceEnabled));
+                    mState = State.COMPLETE;
                 } else {
                     sb.append(mContext.getText(com.android.internal.R.string.mmiError));
                 }
             } else {
                 sb.append(mContext.getText(com.android.internal.R.string.mmiError));
             }
-            mState = State.COMPLETE;
         }
 
         mMessage = sb;
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRcsStatusListener.java b/src/java/com/android/internal/telephony/imsphone/ImsRcsStatusListener.java
new file mode 100644
index 0000000..9fa2f41
--- /dev/null
+++ b/src/java/com/android/internal/telephony/imsphone/ImsRcsStatusListener.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.imsphone;
+
+import com.android.ims.RcsFeatureManager;
+
+/**
+ * A listener to receive IMS RCS status changed.
+ */
+public interface ImsRcsStatusListener {
+    /**
+     * It is called when IMS RCS is connected.
+     */
+    void onRcsConnected(int phoneId, RcsFeatureManager rcsFeatureManager);
+
+    /**
+     * It is called when IMS RCS is disconnected
+     */
+    void onRcsDisconnected(int phoneId);
+}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java b/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java
new file mode 100644
index 0000000..33c16e2
--- /dev/null
+++ b/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 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.imsphone;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.net.Uri;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A helper class to manager the ImsRegistrationCallback can notify the state changed to listener.
+ */
+@AnyThread
+public class ImsRegistrationCallbackHelper {
+    private static final String TAG = "ImsRegCallbackHelper";
+
+    /**
+     * The interface to receive IMS registration updated.
+     */
+    public interface ImsRegistrationUpdate {
+        /**
+         * Handle the callback when IMS is registered.
+         */
+        void handleImsRegistered(int imsRadioTech);
+
+        /**
+         * Handle the callback when IMS is registering.
+         */
+        void handleImsRegistering(int imsRadioTech);
+
+        /**
+         * Handle the callback when IMS is unregistered.
+         */
+        void handleImsUnregistered(ImsReasonInfo imsReasonInfo);
+
+        /**
+         * Handle the callback when the list of subscriber {@link Uri}s associated with this IMS
+         * subscription changed.
+         */
+        void handleImsSubscriberAssociatedUriChanged(Uri[] uris);
+    }
+
+    private ImsRegistrationUpdate mImsRegistrationUpdate;
+    private int mRegistrationState = RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED;
+    private final Object mLock = new Object();
+
+    private final RegistrationManager.RegistrationCallback mImsRegistrationCallback =
+            new RegistrationManager.RegistrationCallback() {
+                @Override
+                public void onRegistered(int imsRadioTech) {
+                    updateRegistrationState(RegistrationManager.REGISTRATION_STATE_REGISTERED);
+                    mImsRegistrationUpdate.handleImsRegistered(imsRadioTech);
+                }
+
+                @Override
+                public void onRegistering(int imsRadioTech) {
+                    updateRegistrationState(RegistrationManager.REGISTRATION_STATE_REGISTERING);
+                    mImsRegistrationUpdate.handleImsRegistering(imsRadioTech);
+                }
+
+                @Override
+                public void onUnregistered(ImsReasonInfo imsReasonInfo) {
+                    updateRegistrationState(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
+                    mImsRegistrationUpdate.handleImsUnregistered(imsReasonInfo);
+                }
+
+                @Override
+                public void onSubscriberAssociatedUriChanged(Uri[] uris) {
+                    mImsRegistrationUpdate.handleImsSubscriberAssociatedUriChanged(uris);
+                }
+            };
+
+    public ImsRegistrationCallbackHelper(@NonNull ImsRegistrationUpdate registrationUpdate,
+            Executor executor) {
+        mImsRegistrationCallback.setExecutor(executor);
+        mImsRegistrationUpdate = registrationUpdate;
+    }
+
+    /**
+     * Reset the IMS registration state.
+     */
+    public void reset() {
+        Log.d(TAG, "reset");
+        updateRegistrationState(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
+    }
+
+    /**
+     * Update the latest IMS registration state.
+     */
+    public synchronized void updateRegistrationState(
+            @RegistrationManager.ImsRegistrationState int newState) {
+        synchronized (mLock) {
+            Log.d(TAG, "updateRegistrationState: registration state from " + mRegistrationState
+                    + " to " + newState);
+            mRegistrationState = newState;
+        }
+    }
+
+    public int getImsRegistrationState() {
+        synchronized (mLock) {
+            return mRegistrationState;
+        }
+    }
+
+    public boolean isImsRegistered() {
+        return getImsRegistrationState() == RegistrationManager.REGISTRATION_STATE_REGISTERED;
+    }
+
+    public RegistrationManager.RegistrationCallback getCallback() {
+        return mImsRegistrationCallback;
+    }
+
+    public IImsRegistrationCallback getCallbackBinder() {
+        return mImsRegistrationCallback.getBinder();
+    }
+}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
index eff2499..3955ea7 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
@@ -20,9 +20,9 @@
 import android.os.Looper;
 import android.os.Message;
 import android.telecom.Connection;
-import android.telephony.Rlog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.telephony.Rlog;
 
 import java.io.IOException;
 import java.nio.channels.ClosedByInterruptException;
diff --git a/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java b/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java
index a3f287c..cf98acb 100644
--- a/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/CallQualityMetrics.java
@@ -18,19 +18,20 @@
 
 import static com.android.internal.telephony.metrics.TelephonyMetrics.toCallQualityProto;
 
-import android.os.Build;
 import android.telephony.CallQuality;
 import android.telephony.CellInfo;
 import android.telephony.CellSignalStrengthLte;
-import android.telephony.Rlog;
 import android.telephony.SignalStrength;
 import android.util.Pair;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * CallQualityMetrics is a utility for tracking the CallQuality during an ongoing call session. It
@@ -42,7 +43,7 @@
     private static final String TAG = CallQualityMetrics.class.getSimpleName();
 
     // certain metrics are only logged on userdebug
-    private static final boolean USERDEBUG_MODE = Build.IS_USERDEBUG;
+    private static final boolean IS_DEBUGGABLE = TelephonyUtils.IS_DEBUGGABLE;
 
     // We only log the first MAX_SNAPSHOTS changes to CallQuality
     private static final int MAX_SNAPSHOTS = 5;
@@ -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.
@@ -116,22 +117,32 @@
             newDlCallQualityState = GOOD_QUALITY;
         }
 
-        if (USERDEBUG_MODE) {
+        if (IS_DEBUGGABLE) {
             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/CallSessionEventBuilder.java b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
index d4bacc6..0aa5fcf 100644
--- a/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
@@ -164,6 +164,13 @@
         return this;
     }
 
+    /** Set the emergency number database version in Ims emergency call information. */
+    public CallSessionEventBuilder setEmergencyNumberDatabaseVersion(
+            int emergencyNumberDatabaseVersion) {
+        mEvent.emergencyNumberDatabaseVersion = emergencyNumberDatabaseVersion;
+        return this;
+    }
+
     /** Set the Ims emergency call information. */
     public CallSessionEventBuilder setImsEmergencyNumberInfo(
             EmergencyNumberInfo imsEmergencyNumberInfo) {
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
index 73439c3..8a423ef 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;
@@ -93,6 +94,12 @@
         return this;
     }
 
+    public TelephonyEventBuilder setSignalStrength(int signalstrength) {
+        mEvent.type = TelephonyEvent.Type.SIGNAL_STRENGTH;
+        mEvent.signalStrength = signalstrength;
+        return this;
+    }
+
     public TelephonyEventBuilder setSetupDataCall(RilSetupDataCall request) {
         mEvent.type = TelephonyEvent.Type.DATA_CALL_SETUP;
         mEvent.setupDataCall = request;
@@ -148,9 +155,11 @@
      * Set and build EMERGENCY_NUMBER_REPORT event
      */
     public TelephonyEventBuilder setUpdatedEmergencyNumber(
-            EmergencyNumberInfo emergencyNumberInfo) {
+            EmergencyNumberInfo emergencyNumberInfo,
+            int emergencyNumberDbVersion) {
         mEvent.type = TelephonyEvent.Type.EMERGENCY_NUMBER_REPORT;
         mEvent.updatedEmergencyNumber = emergencyNumberInfo;
+        mEvent.emergencyNumberDatabaseVersion = emergencyNumberDbVersion;
         return this;
     }
 
@@ -209,4 +218,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..94457f0 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -37,13 +37,13 @@
 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;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.CallQuality;
 import android.telephony.DisconnectCause;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
@@ -72,8 +72,8 @@
 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.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.nano.TelephonyProto;
 import com.android.internal.telephony.nano.TelephonyProto.ActiveSubscriptionInfo;
@@ -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,7 +106,9 @@
 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 com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -207,6 +210,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 +323,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 +445,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 +476,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 +663,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 +904,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;
     }
 
@@ -1139,6 +1152,17 @@
     }
 
     /**
+     * Write SignalStrength event
+     *
+     * @param phoneId Phone id
+     * @param signalStrength Signal strength at the time of data stall recovery
+     */
+    public void writeSignalStrengthEvent(int phoneId, int signalStrength) {
+        addTelephonyEvent(new TelephonyEventBuilder(phoneId)
+                .setSignalStrength(signalStrength).build());
+    }
+
+    /**
      * Write IMS feature settings changed event
      *
      * @param phoneId Phone id
@@ -1531,6 +1555,10 @@
                 call.isEmergencyCall = conn.isEmergencyCall();
                 call.emergencyNumberInfo = convertEmergencyNumberToEmergencyNumberInfo(
                         conn.getEmergencyNumberInfo());
+                EmergencyNumberTracker emergencyNumberTracker = conn.getEmergencyNumberTracker();
+                call.emergencyNumberDatabaseVersion = emergencyNumberTracker != null
+                        ? emergencyNumberTracker.getEmergencyNumberDbVersion()
+                        : TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION;
             }
         }
     }
@@ -2051,6 +2079,9 @@
             cq.averageRelativeJitterMillis = callQuality.getAverageRelativeJitter();
             cq.maxRelativeJitterMillis = callQuality.getMaxRelativeJitter();
             cq.codecType = convertImsCodec(callQuality.getCodecType());
+            cq.rtpInactivityDetected = callQuality.isRtpInactivityDetected();
+            cq.rxSilenceDetected = callQuality.isIncomingSilenceDetected();
+            cq.txSilenceDetected = callQuality.isOutgoingSilenceDetected();
         }
         return cq;
     }
@@ -2082,10 +2113,15 @@
      * @param phoneId Phone id
      * @param session IMS call session
      * @param reasonInfo Call end reason
+     * @param cqm Call Quality Metrics
+     * @param emergencyNumber Emergency Number Info
+     * @param countryIso Network country iso
+     * @param emergencyNumberDatabaseVersion Emergency Number Database Version
      */
     public void writeOnImsCallTerminated(int phoneId, ImsCallSession session,
                                          ImsReasonInfo reasonInfo, CallQualityMetrics cqm,
-                                         EmergencyNumber emergencyNumber, String countryIso) {
+                                         EmergencyNumber emergencyNumber, String countryIso,
+                                         int emergencyNumberDatabaseVersion) {
         InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
         if (callSession == null) {
             Rlog.e(TAG, "Call session is missing");
@@ -2107,6 +2143,8 @@
                     callSessionEvent.setIsImsEmergencyCall(true);
                     callSessionEvent.setImsEmergencyNumberInfo(
                             convertEmergencyNumberToEmergencyNumberInfo(emergencyNumber));
+                    callSessionEvent.setEmergencyNumberDatabaseVersion(
+                            emergencyNumberDatabaseVersion);
                 }
             }
             callSession.addEvent(callSessionEvent);
@@ -2497,7 +2535,8 @@
      *
      * @param emergencyNumber Updated emergency number
      */
-    public void writeEmergencyNumberUpdateEvent(int phoneId, EmergencyNumber emergencyNumber) {
+    public void writeEmergencyNumberUpdateEvent(int phoneId, EmergencyNumber emergencyNumber,
+            int emergencyNumberDatabaseVersion) {
         if (emergencyNumber == null) {
             return;
         }
@@ -2505,7 +2544,25 @@
                 convertEmergencyNumberToEmergencyNumberInfo(emergencyNumber);
 
         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setUpdatedEmergencyNumber(
-                emergencyNumberInfo).build();
+                emergencyNumberInfo, emergencyNumberDatabaseVersion).build();
+        addTelephonyEvent(event);
+    }
+
+    /**
+     * 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);
     }
 
diff --git a/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java b/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java
index 5b41d8e..b6b092c 100644
--- a/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java
+++ b/src/java/com/android/internal/telephony/nitz/NewNitzStateMachineImpl.java
@@ -18,18 +18,18 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.content.Context;
-import android.telephony.Rlog;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.NitzData;
 import com.android.internal.telephony.NitzStateMachine;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TimeZoneLookupHelper;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -83,15 +83,15 @@
     public interface TimeZoneSuggester {
 
         /**
-         * Generates a {@link PhoneTimeZoneSuggestion} given the information available. This method
-         * must always return a non-null {@link PhoneTimeZoneSuggestion} but that object does not
-         * have to contain a time zone if the available information is not sufficient to determine
-         * one. {@link PhoneTimeZoneSuggestion#getDebugInfo()} provides debugging / logging
-         * information explaining the choice.
+         * Generates a {@link TelephonyTimeZoneSuggestion} given the information available. This
+         * method must always return a non-null {@link TelephonyTimeZoneSuggestion} but that object
+         * does not have to contain a time zone if the available information is not sufficient to
+         * determine one. {@link TelephonyTimeZoneSuggestion#getDebugInfo()} provides debugging /
+         * logging information explaining the choice.
          */
         @NonNull
-        PhoneTimeZoneSuggestion getTimeZoneSuggestion(
-                int phoneId, @Nullable String countryIsoCode,
+        TelephonyTimeZoneSuggestion getTimeZoneSuggestion(
+                int slotIndex, @Nullable String countryIsoCode,
                 @Nullable TimestampedValue<NitzData> nitzSignal);
     }
 
@@ -99,10 +99,12 @@
     static final boolean DBG = true;
 
     // Miscellaneous dependencies and helpers not related to detection state.
-    private final int mPhoneId;
+    private final int mSlotIndex;
     /** Applied to NITZ signals during input filtering. */
     private final NitzSignalInputFilterPredicate mNitzSignalInputFilter;
-    /** Creates {@link PhoneTimeZoneSuggestion} for passing to the time zone detection service. */
+    /**
+     * Creates a {@link TelephonyTimeZoneSuggestion} for passing to the time zone detection service.
+     */
     private final TimeZoneSuggester mTimeZoneSuggester;
     /** A facade to the time / time zone detection services. */
     private final NewTimeServiceHelper mNewTimeServiceHelper;
@@ -132,7 +134,7 @@
     public static NewNitzStateMachineImpl createInstance(@NonNull Phone phone) {
         Objects.requireNonNull(phone);
 
-        int phoneId = phone.getPhoneId();
+        int slotIndex = phone.getPhoneId();
         DeviceState deviceState = new DeviceStateImpl(phone);
         TimeZoneLookupHelper timeZoneLookupHelper = new TimeZoneLookupHelper();
         TimeZoneSuggester timeZoneSuggester =
@@ -141,7 +143,7 @@
         NitzSignalInputFilterPredicate nitzSignalFilter =
                 NitzSignalInputFilterPredicateFactory.create(phone.getContext(), deviceState);
         return new NewNitzStateMachineImpl(
-                phoneId, nitzSignalFilter, timeZoneSuggester, newTimeServiceHelper);
+                slotIndex, nitzSignalFilter, timeZoneSuggester, newTimeServiceHelper);
     }
 
     /**
@@ -149,11 +151,11 @@
      * See {@link #createInstance(Phone)}
      */
     @VisibleForTesting
-    public NewNitzStateMachineImpl(int phoneId,
+    public NewNitzStateMachineImpl(int slotIndex,
             @NonNull NitzSignalInputFilterPredicate nitzSignalInputFilter,
             @NonNull TimeZoneSuggester timeZoneSuggester,
             @NonNull NewTimeServiceHelper newTimeServiceHelper) {
-        mPhoneId = phoneId;
+        mSlotIndex = slotIndex;
         mTimeZoneSuggester = Objects.requireNonNull(timeZoneSuggester);
         mNewTimeServiceHelper = Objects.requireNonNull(newTimeServiceHelper);
         mNitzSignalInputFilter = Objects.requireNonNull(nitzSignalInputFilter);
@@ -172,16 +174,26 @@
     }
 
     private void clearNetworkStateAndRerunDetection(String reason) {
-        // Assume any previous NITZ signals received are now invalid.
+        if (mLatestNitzSignal == null) {
+            // The network state is already empty so there's no need to do anything.
+            if (DBG) {
+                Rlog.d(LOG_TAG, reason + ": mLatestNitzSignal was already null. Nothing to do.");
+            }
+            return;
+        }
+
+        // The previous NITZ signal received is now invalid so clear it.
         mLatestNitzSignal = null;
 
+        // countryIsoCode can be assigned null here, in which case the doTimeZoneDetection() call
+        // below will do nothing, which is ok as nothing will have changed.
         String countryIsoCode = mCountryIsoCode;
-
         if (DBG) {
             Rlog.d(LOG_TAG, reason + ": countryIsoCode=" + countryIsoCode);
         }
 
-        // Generate a new time zone suggestion and update the service as needed.
+        // Generate a new time zone suggestion (which could be an empty suggestion) and update the
+        // service as needed.
         doTimeZoneDetection(countryIsoCode, null /* nitzSignal */, reason);
 
         // Generate a new time suggestion and update the service as needed.
@@ -258,7 +270,7 @@
         // will be made after airplane mode is re-enabled as the device re-establishes network
         // connectivity.
 
-        // Clear time zone detection state.
+        // Clear country detection state.
         mCountryIsoCode = null;
 
         String reason = "handleAirplaneModeChanged(" + on + ")";
@@ -274,9 +286,10 @@
         try {
             Objects.requireNonNull(reason);
 
-            PhoneTimeZoneSuggestion suggestion =
-                    mTimeZoneSuggester.getTimeZoneSuggestion(mPhoneId, countryIsoCode, nitzSignal);
+            TelephonyTimeZoneSuggestion suggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    mSlotIndex, countryIsoCode, nitzSignal);
             suggestion.addDebugInfo("Detection reason=" + reason);
+
             if (DBG) {
                 Rlog.d(LOG_TAG, "doTimeZoneDetection: countryIsoCode=" + countryIsoCode
                         + ", nitzSignal=" + nitzSignal + ", suggestion=" + suggestion
@@ -285,7 +298,7 @@
             mNewTimeServiceHelper.maybeSuggestDeviceTimeZone(suggestion);
         } catch (RuntimeException ex) {
             Rlog.e(LOG_TAG, "doTimeZoneDetection: Exception thrown"
-                    + " mPhoneId=" + mPhoneId
+                    + " mSlotIndex=" + mSlotIndex
                     + ", countryIsoCode=" + countryIsoCode
                     + ", nitzSignal=" + nitzSignal
                     + ", reason=" + reason
@@ -300,26 +313,25 @@
             @NonNull String reason) {
         try {
             Objects.requireNonNull(reason);
+
+            TelephonyTimeSuggestion.Builder builder =
+                    new TelephonyTimeSuggestion.Builder(mSlotIndex);
             if (nitzSignal == null) {
-                // Do nothing to withdraw previous suggestions: the service currently does not
-                // support withdrawing suggestions.
-                return;
+                builder.addDebugInfo("Clearing time suggestion"
+                        + " reason=" + reason);
+            } else {
+                TimestampedValue<Long> newNitzTime = new TimestampedValue<>(
+                        nitzSignal.getReferenceTimeMillis(),
+                        nitzSignal.getValue().getCurrentTimeInMillis());
+                builder.setUtcTime(newNitzTime);
+                builder.addDebugInfo("Sending new time suggestion"
+                        + " nitzSignal=" + nitzSignal
+                        + ", reason=" + reason);
             }
-
-            Objects.requireNonNull(nitzSignal.getValue());
-
-            TimestampedValue<Long> newNitzTime = new TimestampedValue<>(
-                    nitzSignal.getReferenceTimeMillis(),
-                    nitzSignal.getValue().getCurrentTimeInMillis());
-            PhoneTimeSuggestion timeSuggestion = new PhoneTimeSuggestion(mPhoneId, newNitzTime);
-            timeSuggestion.addDebugInfo("doTimeDetection: NITZ signal used"
-                    + " nitzSignal=" + nitzSignal
-                    + ", newNitzTime=" + newNitzTime
-                    + ", reason=" + reason);
-            mNewTimeServiceHelper.suggestDeviceTime(timeSuggestion);
+            mNewTimeServiceHelper.suggestDeviceTime(builder.build());
         } catch (RuntimeException ex) {
             Rlog.e(LOG_TAG, "doTimeDetection: Exception thrown"
-                    + " mPhoneId=" + mPhoneId
+                    + " mSlotIndex=" + mSlotIndex
                     + ", nitzSignal=" + nitzSignal
                     + ", reason=" + reason
                     + ", ex=" + ex, ex);
diff --git a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java
index 7984c97..8d827ee 100644
--- a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java
+++ b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelper.java
@@ -17,10 +17,10 @@
 package com.android.internal.telephony.nitz;
 
 import android.annotation.NonNull;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
 import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
@@ -36,17 +36,18 @@
      *
      * @param suggestion the time
      */
-    void suggestDeviceTime(@NonNull PhoneTimeSuggestion suggestion);
+    void suggestDeviceTime(@NonNull TelephonyTimeSuggestion suggestion);
 
     /**
      * Suggests the time zone to the time zone detector.
      *
-     * <p>NOTE: The PhoneTimeZoneSuggestion cannot be null. The zoneId it contains can be null to
-     * indicate there is no active suggestion; this can be used to clear a previous suggestion.
+     * <p>NOTE: The {@link TelephonyTimeZoneSuggestion} cannot be null. The zoneId it contains can
+     * be null to indicate there is no active suggestion; this can be used to clear a previous
+     * suggestion.
      *
      * @param suggestion the time zone
      */
-    void maybeSuggestDeviceTimeZone(@NonNull PhoneTimeZoneSuggestion suggestion);
+    void maybeSuggestDeviceTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
 
     /**
      * Dumps any logs held to the supplied writer.
diff --git a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java
index 337423b..31e450d 100644
--- a/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java
+++ b/src/java/com/android/internal/telephony/nitz/NewTimeServiceHelperImpl.java
@@ -18,16 +18,16 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
 import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.content.Context;
+import android.os.TimestampedValue;
 import android.util.LocalLog;
-import android.util.TimestampedValue;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
-import com.android.internal.telephony.nitz.service.TimeZoneDetectionService;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
@@ -38,12 +38,12 @@
  */
 public final class NewTimeServiceHelperImpl implements NewTimeServiceHelper {
 
-    private final int mPhoneId;
+    private final int mSlotIndex;
     private final TimeDetector mTimeDetector;
-    private final TimeZoneDetectionService mTimeZoneDetector;
+    private final TimeZoneDetector mTimeZoneDetector;
 
-    private final LocalLog mTimeZoneLog = new LocalLog(30);
-    private final LocalLog mTimeLog = new LocalLog(30);
+    private final LocalLog mTimeZoneLog = new LocalLog(30, false /* mUseLocalTimestamps */);
+    private final LocalLog mTimeLog = new LocalLog(30, false /* mUseLocalTimestamps */);
 
     /**
      * Records the last time zone suggestion made. Used to avoid sending duplicate suggestions to
@@ -51,42 +51,44 @@
      * been made.
      */
     @NonNull
-    private PhoneTimeZoneSuggestion mLastSuggestedTimeZone;
+    private TelephonyTimeZoneSuggestion mLastSuggestedTimeZone;
 
     public NewTimeServiceHelperImpl(@NonNull Phone phone) {
-        mPhoneId = phone.getPhoneId();
+        mSlotIndex = phone.getPhoneId();
         Context context = Objects.requireNonNull(phone.getContext());
         mTimeDetector = Objects.requireNonNull(context.getSystemService(TimeDetector.class));
-        mTimeZoneDetector = Objects.requireNonNull(TimeZoneDetectionService.getInstance(context));
+        mTimeZoneDetector =
+                Objects.requireNonNull(context.getSystemService(TimeZoneDetector.class));
     }
 
     @Override
-    public void suggestDeviceTime(@NonNull PhoneTimeSuggestion phoneTimeSuggestion) {
-        mTimeLog.log("Suggesting system clock update: " + phoneTimeSuggestion);
+    public void suggestDeviceTime(@NonNull TelephonyTimeSuggestion timeSuggestion) {
+        mTimeLog.log("Sending time suggestion: " + timeSuggestion);
 
-        // 3 nullness assertions in 1 line
-        Objects.requireNonNull(phoneTimeSuggestion.getUtcTime().getValue());
+        Objects.requireNonNull(timeSuggestion);
 
-        TimestampedValue<Long> utcTime = phoneTimeSuggestion.getUtcTime();
-        TelephonyMetrics.getInstance().writeNITZEvent(mPhoneId, utcTime.getValue());
-        mTimeDetector.suggestPhoneTime(phoneTimeSuggestion);
+        if (timeSuggestion.getUtcTime() != null) {
+            TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime();
+            TelephonyMetrics.getInstance().writeNITZEvent(mSlotIndex, utcTime.getValue());
+        }
+        mTimeDetector.suggestTelephonyTime(timeSuggestion);
     }
 
     @Override
-    public void maybeSuggestDeviceTimeZone(@NonNull PhoneTimeZoneSuggestion newSuggestion) {
+    public void maybeSuggestDeviceTimeZone(@NonNull TelephonyTimeZoneSuggestion newSuggestion) {
         Objects.requireNonNull(newSuggestion);
 
-        PhoneTimeZoneSuggestion oldSuggestion = mLastSuggestedTimeZone;
+        TelephonyTimeZoneSuggestion oldSuggestion = mLastSuggestedTimeZone;
         if (shouldSendNewTimeZoneSuggestion(oldSuggestion, newSuggestion)) {
             mTimeZoneLog.log("Suggesting time zone update: " + newSuggestion);
-            mTimeZoneDetector.suggestPhoneTimeZone(newSuggestion);
+            mTimeZoneDetector.suggestTelephonyTimeZone(newSuggestion);
             mLastSuggestedTimeZone = newSuggestion;
         }
     }
 
     private static boolean shouldSendNewTimeZoneSuggestion(
-            @Nullable PhoneTimeZoneSuggestion oldSuggestion,
-            @NonNull PhoneTimeZoneSuggestion newSuggestion) {
+            @Nullable TelephonyTimeZoneSuggestion oldSuggestion,
+            @NonNull TelephonyTimeZoneSuggestion newSuggestion) {
         if (oldSuggestion == null) {
             // No previous suggestion.
             return true;
@@ -109,14 +111,10 @@
         mTimeZoneLog.dump(ipw);
         ipw.decreaseIndent();
         ipw.decreaseIndent();
-
-        // TODO Remove this line when the service moves to the system server.
-        mTimeZoneDetector.dumpLogs(ipw);
     }
 
     @Override
     public void dumpState(PrintWriter pw) {
         pw.println(" NewTimeServiceHelperImpl.mLastSuggestedTimeZone=" + mLastSuggestedTimeZone);
-        mTimeZoneDetector.dumpState(pw);
     }
 }
diff --git a/src/java/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactory.java b/src/java/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactory.java
index 58cbaaa..5c238b7 100644
--- a/src/java/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactory.java
+++ b/src/java/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactory.java
@@ -21,13 +21,13 @@
 import android.content.Context;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
-import android.telephony.Rlog;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.NitzData;
 import com.android.internal.telephony.NitzStateMachine.DeviceState;
 import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.NitzSignalInputFilterPredicate;
+import com.android.telephony.Rlog;
 
 import java.util.Arrays;
 import java.util.Objects;
diff --git a/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java b/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java
index c5d9df6..a01f09b 100644
--- a/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java
+++ b/src/java/com/android/internal/telephony/nitz/TimeZoneSuggesterImpl.java
@@ -16,17 +16,14 @@
 
 package com.android.internal.telephony.nitz;
 
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_DEFAULT_BOOSTED;
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS;
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_MULTIPLE_ZONES_SAME_OFFSET;
-import static com.android.internal.telephony.TimeZoneLookupHelper.CountryResult.QUALITY_SINGLE_ZONE;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.createEmptySuggestion;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.createEmptySuggestion;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.telephony.Rlog;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.os.TimestampedValue;
 import android.text.TextUtils;
-import android.util.TimestampedValue;
+import android.timezone.CountryTimeZones.OffsetResult;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.NitzData;
@@ -34,7 +31,7 @@
 import com.android.internal.telephony.TimeZoneLookupHelper;
 import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
 import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.TimeZoneSuggester;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
+import com.android.telephony.Rlog;
 
 import java.util.Objects;
 
@@ -58,44 +55,46 @@
 
     @Override
     @NonNull
-    public PhoneTimeZoneSuggestion getTimeZoneSuggestion(int phoneId,
+    public TelephonyTimeZoneSuggestion getTimeZoneSuggestion(int slotIndex,
             @Nullable String countryIsoCode, @Nullable TimestampedValue<NitzData> nitzSignal) {
         try {
             // Check for overriding NITZ-based signals from Android running in an emulator.
-            PhoneTimeZoneSuggestion overridingSuggestion = null;
+            TelephonyTimeZoneSuggestion overridingSuggestion = null;
             if (nitzSignal != null) {
                 NitzData nitzData = nitzSignal.getValue();
                 if (nitzData.getEmulatorHostTimeZone() != null) {
-                    overridingSuggestion = new PhoneTimeZoneSuggestion(phoneId);
-                    overridingSuggestion.setZoneId(nitzData.getEmulatorHostTimeZone().getID());
-                    overridingSuggestion.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-                    overridingSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-                    overridingSuggestion.addDebugInfo("Emulator time zone override: " + nitzData);
+                    TelephonyTimeZoneSuggestion.Builder builder =
+                            new TelephonyTimeZoneSuggestion.Builder(slotIndex)
+                            .setZoneId(nitzData.getEmulatorHostTimeZone().getID())
+                            .setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID)
+                            .setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
+                            .addDebugInfo("Emulator time zone override: " + nitzData);
+                    overridingSuggestion = builder.build();
                 }
             }
 
-            PhoneTimeZoneSuggestion suggestion;
+            TelephonyTimeZoneSuggestion suggestion;
             if (overridingSuggestion != null) {
                 suggestion = overridingSuggestion;
             } else if (countryIsoCode == null) {
                 if (nitzSignal == null) {
-                    suggestion = createEmptySuggestion(phoneId,
+                    suggestion = createEmptySuggestion(slotIndex,
                             "getTimeZoneSuggestion: nitzSignal=null, countryIsoCode=null");
                 } else {
                     // NITZ only - wait until we have a country.
-                    suggestion = createEmptySuggestion(phoneId, "getTimeZoneSuggestion:"
+                    suggestion = createEmptySuggestion(slotIndex, "getTimeZoneSuggestion:"
                             + " nitzSignal=" + nitzSignal + ", countryIsoCode=null");
                 }
             } else { // countryIsoCode != null
                 if (nitzSignal == null) {
                     if (countryIsoCode.isEmpty()) {
                         // This is assumed to be a test network with no NITZ data to go on.
-                        suggestion = createEmptySuggestion(phoneId,
+                        suggestion = createEmptySuggestion(slotIndex,
                                 "getTimeZoneSuggestion: nitzSignal=null, countryIsoCode=\"\"");
                     } else {
                         // Country only
                         suggestion = findTimeZoneFromNetworkCountryCode(
-                                phoneId, countryIsoCode, mDeviceState.currentTimeMillis());
+                                slotIndex, countryIsoCode, mDeviceState.currentTimeMillis());
                     }
                 } else { // nitzSignal != null
                     if (countryIsoCode.isEmpty()) {
@@ -104,11 +103,11 @@
                         // (eg, "001"). Obtain a TimeZone based only on the NITZ parameters: without
                         // a country it will be arbitrary, but it should at least have the correct
                         // offset.
-                        suggestion = findTimeZoneForTestNetwork(phoneId, nitzSignal);
+                        suggestion = findTimeZoneForTestNetwork(slotIndex, nitzSignal);
                     } else {
                         // We have both NITZ and Country code.
                         suggestion = findTimeZoneFromCountryAndNitz(
-                                phoneId, countryIsoCode, nitzSignal);
+                                slotIndex, countryIsoCode, nitzSignal);
                     }
                 }
             }
@@ -124,72 +123,80 @@
                     + " countryIsoCode=" + countryIsoCode
                     + ", nitzSignal=" + nitzSignal
                     + ", e=" + e.getMessage();
-            PhoneTimeZoneSuggestion errorSuggestion = createEmptySuggestion(phoneId, message);
-            errorSuggestion.addDebugInfo(message);
+            TelephonyTimeZoneSuggestion errorSuggestion = createEmptySuggestion(slotIndex, message);
             Rlog.w(LOG_TAG, message, e);
             return errorSuggestion;
         }
     }
 
     /**
-     * Creates a {@link PhoneTimeZoneSuggestion} using only NITZ. This happens when the device
+     * Creates a {@link TelephonyTimeZoneSuggestion} using only NITZ. This happens when the device
      * is attached to a test cell with an unrecognized MCC. In these cases we try to return a
      * suggestion for an arbitrary time zone that matches the NITZ offset information.
      */
     @NonNull
-    private PhoneTimeZoneSuggestion findTimeZoneForTestNetwork(
-            int phoneId, @NonNull TimestampedValue<NitzData> nitzSignal) {
+    private TelephonyTimeZoneSuggestion findTimeZoneForTestNetwork(
+            int slotIndex, @NonNull TimestampedValue<NitzData> nitzSignal) {
         Objects.requireNonNull(nitzSignal);
         NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());
 
-        PhoneTimeZoneSuggestion result = new PhoneTimeZoneSuggestion(phoneId);
-        result.addDebugInfo("findTimeZoneForTestNetwork: nitzSignal=" + nitzSignal);
-        TimeZoneLookupHelper.OffsetResult lookupResult =
+        TelephonyTimeZoneSuggestion.Builder suggestionBuilder =
+                new TelephonyTimeZoneSuggestion.Builder(slotIndex);
+        suggestionBuilder.addDebugInfo("findTimeZoneForTestNetwork: nitzSignal=" + nitzSignal);
+        OffsetResult lookupResult =
                 mTimeZoneLookupHelper.lookupByNitz(nitzData);
         if (lookupResult == null) {
-            result.addDebugInfo("findTimeZoneForTestNetwork: No zone found");
+            suggestionBuilder.addDebugInfo("findTimeZoneForTestNetwork: No zone found");
         } else {
-            result.setZoneId(lookupResult.getTimeZone().getID());
-            result.setMatchType(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY);
-            int quality = lookupResult.getIsOnlyMatch() ? PhoneTimeZoneSuggestion.SINGLE_ZONE
-                    : PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-            result.setQuality(quality);
-            result.addDebugInfo("findTimeZoneForTestNetwork: lookupResult=" + lookupResult);
+            suggestionBuilder.setZoneId(lookupResult.getTimeZone().getID());
+            suggestionBuilder.setMatchType(
+                    TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY);
+            int quality = lookupResult.isOnlyMatch()
+                    ? TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE
+                    : TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+            suggestionBuilder.setQuality(quality);
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneForTestNetwork: lookupResult=" + lookupResult);
         }
-        return result;
+        return suggestionBuilder.build();
     }
 
     /**
-     * Creates a {@link PhoneTimeZoneSuggestion} using network country code and NITZ.
+     * Creates a {@link TelephonyTimeZoneSuggestion} using network country code and NITZ.
      */
     @NonNull
-    private PhoneTimeZoneSuggestion findTimeZoneFromCountryAndNitz(
-            int phoneId, @NonNull String countryIsoCode,
+    private TelephonyTimeZoneSuggestion findTimeZoneFromCountryAndNitz(
+            int slotIndex, @NonNull String countryIsoCode,
             @NonNull TimestampedValue<NitzData> nitzSignal) {
         Objects.requireNonNull(countryIsoCode);
         Objects.requireNonNull(nitzSignal);
 
-        PhoneTimeZoneSuggestion suggestion = new PhoneTimeZoneSuggestion(phoneId);
-        suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: countryIsoCode=" + countryIsoCode
+        TelephonyTimeZoneSuggestion.Builder suggestionBuilder =
+                new TelephonyTimeZoneSuggestion.Builder(slotIndex);
+        suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz:"
+                + " countryIsoCode=" + countryIsoCode
                 + ", nitzSignal=" + nitzSignal);
         NitzData nitzData = Objects.requireNonNull(nitzSignal.getValue());
         if (isNitzSignalOffsetInfoBogus(countryIsoCode, nitzData)) {
-            suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: NITZ signal looks bogus");
-            return suggestion;
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneFromCountryAndNitz: NITZ signal looks bogus");
+            return suggestionBuilder.build();
         }
 
         // Try to find a match using both country + NITZ signal.
-        TimeZoneLookupHelper.OffsetResult lookupResult =
+        OffsetResult lookupResult =
                 mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, countryIsoCode);
         if (lookupResult != null) {
-            suggestion.setZoneId(lookupResult.getTimeZone().getID());
-            suggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            int quality = lookupResult.getIsOnlyMatch()
-                    ? PhoneTimeZoneSuggestion.SINGLE_ZONE
-                    : PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-            suggestion.setQuality(quality);
-            suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: lookupResult=" + lookupResult);
-            return suggestion;
+            suggestionBuilder.setZoneId(lookupResult.getTimeZone().getID());
+            suggestionBuilder.setMatchType(
+                    TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
+            int quality = lookupResult.isOnlyMatch()
+                    ? TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE
+                    : TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+            suggestionBuilder.setQuality(quality);
+            suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz:"
+                    + " lookupResult=" + lookupResult);
+            return suggestionBuilder.build();
         }
 
         // The country + offset provided no match, so see if the country by itself would be enough.
@@ -197,75 +204,81 @@
                 countryIsoCode, nitzData.getCurrentTimeInMillis());
         if (countryResult == null) {
             // Country not recognized.
-            suggestion.addDebugInfo(
+            suggestionBuilder.addDebugInfo(
                     "findTimeZoneFromCountryAndNitz: lookupByCountry() country not recognized");
-            return suggestion;
+            return suggestionBuilder.build();
         }
 
         // If the country has a single zone, or it has multiple zones but the default zone is
         // "boosted" (i.e. the country default is considered a good suggestion in most cases) then
         // use it.
-        if (countryResult.quality == QUALITY_SINGLE_ZONE
-                || countryResult.quality == QUALITY_DEFAULT_BOOSTED) {
-            suggestion.setZoneId(countryResult.zoneId);
-            suggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            suggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            suggestion.addDebugInfo(
+        if (countryResult.quality == CountryResult.QUALITY_SINGLE_ZONE
+                || countryResult.quality == CountryResult.QUALITY_DEFAULT_BOOSTED) {
+            suggestionBuilder.setZoneId(countryResult.zoneId);
+            suggestionBuilder.setMatchType(
+                    TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+            suggestionBuilder.setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+            suggestionBuilder.addDebugInfo(
                     "findTimeZoneFromCountryAndNitz: high quality country-only suggestion:"
                             + " countryResult=" + countryResult);
-            return suggestion;
+            return suggestionBuilder.build();
         }
 
         // Quality is not high enough to set the zone using country only.
-        suggestion.addDebugInfo("findTimeZoneFromCountryAndNitz: country-only suggestion quality"
-                + " not high enough. countryResult=" + countryResult);
-        return suggestion;
+        suggestionBuilder.addDebugInfo("findTimeZoneFromCountryAndNitz: country-only suggestion"
+                + " quality not high enough. countryResult=" + countryResult);
+        return suggestionBuilder.build();
     }
 
     /**
-     * Creates a {@link PhoneTimeZoneSuggestion} using only network country code; works well on
+     * Creates a {@link TelephonyTimeZoneSuggestion} using only network country code; works well on
      * countries which only have one time zone or multiple zones with the same offset.
      *
      * @param countryIsoCode country code from network MCC
      * @param whenMillis the time to use when looking at time zone rules data
      */
     @NonNull
-    private PhoneTimeZoneSuggestion findTimeZoneFromNetworkCountryCode(
-            int phoneId, @NonNull String countryIsoCode, long whenMillis) {
+    private TelephonyTimeZoneSuggestion findTimeZoneFromNetworkCountryCode(
+            int slotIndex, @NonNull String countryIsoCode, long whenMillis) {
         Objects.requireNonNull(countryIsoCode);
         if (TextUtils.isEmpty(countryIsoCode)) {
             throw new IllegalArgumentException("countryIsoCode must not be empty");
         }
 
-        PhoneTimeZoneSuggestion result = new PhoneTimeZoneSuggestion(phoneId);
-        result.addDebugInfo("findTimeZoneFromNetworkCountryCode:"
+        TelephonyTimeZoneSuggestion.Builder suggestionBuilder =
+                new TelephonyTimeZoneSuggestion.Builder(slotIndex);
+        suggestionBuilder.addDebugInfo("findTimeZoneFromNetworkCountryCode:"
                 + " whenMillis=" + whenMillis + ", countryIsoCode=" + countryIsoCode);
         CountryResult lookupResult = mTimeZoneLookupHelper.lookupByCountry(
                 countryIsoCode, whenMillis);
         if (lookupResult != null) {
-            result.setZoneId(lookupResult.zoneId);
-            result.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
+            suggestionBuilder.setZoneId(lookupResult.zoneId);
+            suggestionBuilder.setMatchType(
+                    TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
 
             int quality;
-            if (lookupResult.quality == QUALITY_SINGLE_ZONE
-                    || lookupResult.quality == QUALITY_DEFAULT_BOOSTED) {
-                quality = PhoneTimeZoneSuggestion.SINGLE_ZONE;
-            } else if (lookupResult.quality == QUALITY_MULTIPLE_ZONES_SAME_OFFSET) {
-                quality = PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-            } else if (lookupResult.quality == QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS) {
-                quality = PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+            if (lookupResult.quality == CountryResult.QUALITY_SINGLE_ZONE
+                    || lookupResult.quality == CountryResult.QUALITY_DEFAULT_BOOSTED) {
+                quality = TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+            } else if (lookupResult.quality == CountryResult.QUALITY_MULTIPLE_ZONES_SAME_OFFSET) {
+                quality = TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+            } else if (lookupResult.quality
+                    == CountryResult.QUALITY_MULTIPLE_ZONES_DIFFERENT_OFFSETS) {
+                quality = TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
             } else {
                 // This should never happen.
                 throw new IllegalArgumentException(
                         "lookupResult.quality not recognized: countryIsoCode=" + countryIsoCode
                                 + ", whenMillis=" + whenMillis + ", lookupResult=" + lookupResult);
             }
-            result.setQuality(quality);
-            result.addDebugInfo("findTimeZoneFromNetworkCountryCode: lookupResult=" + lookupResult);
+            suggestionBuilder.setQuality(quality);
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneFromNetworkCountryCode: lookupResult=" + lookupResult);
         } else {
-            result.addDebugInfo("findTimeZoneFromNetworkCountryCode: Country not recognized?");
+            suggestionBuilder.addDebugInfo(
+                    "findTimeZoneFromNetworkCountryCode: Country not recognized?");
         }
-        return result;
+        return suggestionBuilder.build();
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestion.java b/src/java/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestion.java
deleted file mode 100644
index a5078a7..0000000
--- a/src/java/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestion.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright 2019 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.nitz.service;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information.
- */
-public final class PhoneTimeZoneSuggestion implements Parcelable {
-
-    public static final Creator<PhoneTimeZoneSuggestion> CREATOR =
-            new Creator<PhoneTimeZoneSuggestion>() {
-                public PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
-                    return PhoneTimeZoneSuggestion.createFromParcel(in);
-                }
-
-                public PhoneTimeZoneSuggestion[] newArray(int size) {
-                    return new PhoneTimeZoneSuggestion[size];
-                }
-            };
-
-    /**
-     * Creates an empty time zone suggestion, i.e. one that will cancel previous suggestions with
-     * the same {@code phoneId}.
-     */
-    @NonNull
-    public static PhoneTimeZoneSuggestion createEmptySuggestion(
-            int phoneId, @NonNull String debugInfo) {
-        PhoneTimeZoneSuggestion timeZoneSuggestion = new PhoneTimeZoneSuggestion(phoneId);
-        timeZoneSuggestion.addDebugInfo(debugInfo);
-        return timeZoneSuggestion;
-    }
-
-    @IntDef({ MATCH_TYPE_NA, NETWORK_COUNTRY_ONLY, NETWORK_COUNTRY_AND_OFFSET, EMULATOR_ZONE_ID,
-            TEST_NETWORK_OFFSET_ONLY })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MatchType {}
-
-    /** Used when match type is not applicable. */
-    public static final int MATCH_TYPE_NA = 0;
-
-    /**
-     * Only the network country is known.
-     */
-    public static final int NETWORK_COUNTRY_ONLY = 2;
-
-    /**
-     * Both the network county and offset were known.
-     */
-    public static final int NETWORK_COUNTRY_AND_OFFSET = 3;
-
-    /**
-     * The device is running in an emulator and an NITZ signal was simulated containing an
-     * Android extension with an explicit Olson ID.
-     */
-    public static final int EMULATOR_ZONE_ID = 4;
-
-    /**
-     * The phone is most likely running in a test network not associated with a country (this is
-     * distinct from the country just not being known yet).
-     * Historically, Android has just picked an arbitrary time zone with the correct offset when
-     * on a test network.
-     */
-    public static final int TEST_NETWORK_OFFSET_ONLY = 5;
-
-    @IntDef({ QUALITY_NA, SINGLE_ZONE, MULTIPLE_ZONES_WITH_SAME_OFFSET,
-            MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Quality {}
-
-    /** Used when quality is not applicable. */
-    public static final int QUALITY_NA = 0;
-
-    /** There is only one answer */
-    public static final int SINGLE_ZONE = 1;
-
-    /**
-     * There are multiple answers, but they all shared the same offset / DST state at the time
-     * the suggestion was created. i.e. it might be the wrong zone but the user won't notice
-     * immediately if it is wrong.
-     */
-    public static final int MULTIPLE_ZONES_WITH_SAME_OFFSET = 2;
-
-    /**
-     * There are multiple answers with different offsets. The one given is just one possible.
-     */
-    public static final int MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3;
-
-    /**
-     * The ID of the phone this suggestion is associated with. For multiple-sim devices this
-     * helps to establish origin so filtering / stickiness can be implemented.
-     */
-    private final int mPhoneId;
-
-    /**
-     * The suggestion. {@code null} means there is no current suggestion and any previous suggestion
-     * should be forgotten.
-     */
-    private String mZoneId;
-
-    /**
-     * The type of "match" used to establish the time zone.
-     */
-    @MatchType
-    private int mMatchType;
-
-    /**
-     * A measure of the quality of the time zone suggestion, i.e. how confident one could be in
-     * it.
-     */
-    @Quality
-    private int mQuality;
-
-    /**
-     * Free-form debug information about how the signal was derived. Used for debug only,
-     * intentionally not used in equals(), etc.
-     */
-    private List<String> mDebugInfo;
-
-    public PhoneTimeZoneSuggestion(int phoneId) {
-        this.mPhoneId = phoneId;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
-        int phoneId = in.readInt();
-        PhoneTimeZoneSuggestion phoneTimeZoneSuggestion = new PhoneTimeZoneSuggestion(phoneId);
-        phoneTimeZoneSuggestion.mZoneId = in.readString();
-        phoneTimeZoneSuggestion.mMatchType = in.readInt();
-        phoneTimeZoneSuggestion.mQuality = in.readInt();
-        phoneTimeZoneSuggestion.mDebugInfo =
-                (List<String>) in.readArrayList(PhoneTimeZoneSuggestion.class.getClassLoader());
-        return phoneTimeZoneSuggestion;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mPhoneId);
-        dest.writeString(mZoneId);
-        dest.writeInt(mMatchType);
-        dest.writeInt(mQuality);
-        dest.writeList(mDebugInfo);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    public int getPhoneId() {
-        return mPhoneId;
-    }
-
-    @Nullable
-    public String getZoneId() {
-        return mZoneId;
-    }
-
-    public void setZoneId(@Nullable String zoneId) {
-        this.mZoneId = zoneId;
-    }
-
-
-    @MatchType
-    public int getMatchType() {
-        return mMatchType;
-    }
-
-    public void setMatchType(@MatchType int matchType) {
-        this.mMatchType = matchType;
-    }
-    @Quality
-    public int getQuality() {
-        return mQuality;
-    }
-
-    public void setQuality(@Quality int quality) {
-        this.mQuality = quality;
-    }
-
-    public List<String> getDebugInfo() {
-        return Collections.unmodifiableList(mDebugInfo);
-    }
-
-    /**
-     * Associates information with the instance that can be useful for debugging / logging. The
-     * information is present in {@link #toString()} but is not considered for
-     * {@link #equals(Object)} and {@link #hashCode()}.
-     */
-    public void addDebugInfo(String... debugInfos) {
-        if (mDebugInfo == null) {
-            mDebugInfo = new ArrayList<>();
-        }
-        mDebugInfo.addAll(Arrays.asList(debugInfos));
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        PhoneTimeZoneSuggestion that = (PhoneTimeZoneSuggestion) o;
-        return mPhoneId == that.mPhoneId
-                && mMatchType == that.mMatchType
-                && mQuality == that.mQuality
-                && Objects.equals(mZoneId, that.mZoneId);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mPhoneId, mZoneId, mMatchType, mQuality);
-    }
-
-    @Override
-    public String toString() {
-        return "PhoneTimeZoneSuggestion{"
-                + "mPhoneId=" + mPhoneId
-                + ", mZoneId='" + mZoneId + '\''
-                + ", mMatchType=" + mMatchType
-                + ", mQuality=" + mQuality
-                + ", mDebugInfo=" + mDebugInfo
-                + '}';
-    }
-}
diff --git a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionService.java b/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionService.java
deleted file mode 100644
index a766d9a..0000000
--- a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionService.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright 2019 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.nitz.service;
-
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MATCH_TYPE_NA;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.QUALITY_NA;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.SINGLE_ZONE;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.PrintWriter;
-import java.util.LinkedList;
-import java.util.Objects;
-
-/**
- * A singleton, stateful time zone detection service that is aware of multiple phone devices. It
- * keeps track of the most recent suggestion from each phone and it uses the best based on a scoring
- * algorithm. If both phones provide the same score then the phone with the lowest numeric ID
- * "wins". If the situation changes and it is no longer possible to be confident about the time
- * zone, phones must submit an empty suggestion in order to "withdraw" their previous suggestion.
- *
- * <p>Ultimately, this responsibility will be moved to system server and then it will be extended /
- * rewritten to handle non-telephony time zone signals.
- */
-public class TimeZoneDetectionService {
-
-    /**
-     * Used by {@link TimeZoneDetectionService} to interact with device settings. It can be faked
-     * for tests.
-     */
-    @VisibleForTesting
-    public interface Helper {
-
-        /**
-         * Callback interface for automatic detection enable/disable changes.
-         */
-        interface Listener {
-            /**
-             * Automatic time zone detection has been enabled or disabled.
-             */
-            void onTimeZoneDetectionChange(boolean enabled);
-        }
-
-        /**
-         * Sets a listener that will be called when the automatic time / time zone detection setting
-         * changes.
-         */
-        void setListener(Listener listener);
-
-        /**
-         * Returns true if automatic time zone detection is enabled in settings.
-         */
-        boolean isTimeZoneDetectionEnabled();
-
-        /**
-         * Returns true if the device has had an explicit time zone set.
-         */
-        boolean isTimeZoneSettingInitialized();
-
-        /**
-         * Set the device time zone from the suggestion as needed.
-         */
-        void setDeviceTimeZoneFromSuggestion(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion);
-
-        /**
-         * Dumps any logs held to the supplied writer.
-         */
-        void dumpLogs(IndentingPrintWriter ipw);
-
-        /**
-         * Dumps internal state such as field values.
-         */
-        void dumpState(PrintWriter pw);
-    }
-
-    static final String LOG_TAG = "TimeZoneDetectionService";
-    static final boolean DBG = true;
-
-    /**
-     * The abstract score for an empty or invalid suggestion.
-     *
-     * Used to score suggestions where there is no zone.
-     */
-    @VisibleForTesting
-    public static final int SCORE_NONE = 0;
-
-    /**
-     * The abstract score for a low quality suggestion.
-     *
-     * Used to score suggestions where:
-     * The suggested zone ID is one of several possibilities, and the possibilities have different
-     * offsets.
-     *
-     * You would have to be quite desperate to want to use this choice.
-     */
-    @VisibleForTesting
-    public static final int SCORE_LOW = 1;
-
-    /**
-     * The abstract score for a medium quality suggestion.
-     *
-     * Used for:
-     * The suggested zone ID is one of several possibilities but at least the possibilities have the
-     * same offset. Users would get the correct time but for the wrong reason. i.e. their device may
-     * switch to DST at the wrong time and (for example) their calendar events.
-     */
-    @VisibleForTesting
-    public static final int SCORE_MEDIUM = 2;
-
-    /**
-     * The abstract score for a high quality suggestion.
-     *
-     * Used for:
-     * The suggestion was for one zone ID and the answer was unambiguous and likely correct given
-     * the info available.
-     */
-    @VisibleForTesting
-    public static final int SCORE_HIGH = 3;
-
-    /**
-     * The abstract score for a highest quality suggestion.
-     *
-     * Used for:
-     * Suggestions that must "win" because they constitute test or emulator zone ID.
-     */
-    @VisibleForTesting
-    public static final int SCORE_HIGHEST = 4;
-
-    /** The threshold at which suggestions are good enough to use to set the device's time zone. */
-    @VisibleForTesting
-    public static final int SCORE_USAGE_THRESHOLD = SCORE_MEDIUM;
-
-    /** The singleton instance. */
-    private static TimeZoneDetectionService sInstance;
-
-    /**
-     * Returns the singleton instance, constructing as needed with the supplied context.
-     */
-    public static synchronized TimeZoneDetectionService getInstance(Context context) {
-        if (sInstance == null) {
-            Helper timeZoneDetectionServiceHelper = new TimeZoneDetectionServiceHelperImpl(context);
-            sInstance = new TimeZoneDetectionService(timeZoneDetectionServiceHelper);
-        }
-        return sInstance;
-    }
-
-    private static final int KEEP_SUGGESTION_HISTORY_SIZE = 30;
-
-    /**
-     * A mapping from phoneId to a linked list of time zone suggestions (the head being the latest).
-     * We typically expect one or two entries in this Map: devices will have a small number
-     * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with
-     * the ID will not exceed {@link #KEEP_SUGGESTION_HISTORY_SIZE} in size.
-     */
-    @GuardedBy("this")
-    private ArrayMap<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> mSuggestionByPhoneId =
-            new ArrayMap<>();
-
-    /**
-     * The most recent best guess of time zone from all phones. Can be {@code null} to indicate
-     * there would be no current suggestion.
-     */
-    @GuardedBy("this")
-    @Nullable
-    private QualifiedPhoneTimeZoneSuggestion mCurrentSuggestion;
-
-    // Dependencies and log state.
-    private final Helper mTimeZoneDetectionServiceHelper;
-
-    @VisibleForTesting
-    public TimeZoneDetectionService(Helper timeZoneDetectionServiceHelper) {
-        mTimeZoneDetectionServiceHelper = timeZoneDetectionServiceHelper;
-        mTimeZoneDetectionServiceHelper.setListener(enabled -> {
-            if (enabled) {
-                handleAutoTimeZoneEnabled();
-            }
-        });
-    }
-
-    /**
-     * Suggests a time zone for the device, or withdraws a previous suggestion if
-     * {@link PhoneTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to a
-     * specific {@link PhoneTimeZoneSuggestion#getPhoneId() phone}.
-     * See {@link PhoneTimeZoneSuggestion} for an explanation of the metadata associated with a
-     * suggestion. The service uses suggestions to decide whether to modify the device's time zone
-     * setting and what to set it to.
-     */
-    public synchronized void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion newSuggestion) {
-        if (DBG) {
-            Log.d(LOG_TAG, "suggestPhoneTimeZone: newSuggestion=" + newSuggestion);
-        }
-        Objects.requireNonNull(newSuggestion);
-
-        int score = scoreSuggestion(newSuggestion);
-        QualifiedPhoneTimeZoneSuggestion scoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(newSuggestion, score);
-
-        // Record the suggestion against the correct phoneId.
-        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
-                mSuggestionByPhoneId.get(newSuggestion.getPhoneId());
-        if (suggestions == null) {
-            suggestions = new LinkedList<>();
-            mSuggestionByPhoneId.put(newSuggestion.getPhoneId(), suggestions);
-        }
-        suggestions.addFirst(scoredSuggestion);
-        if (suggestions.size() > KEEP_SUGGESTION_HISTORY_SIZE) {
-            suggestions.removeLast();
-        }
-
-        // Now run the competition between the phones' suggestions.
-        doTimeZoneDetection();
-    }
-
-    private static int scoreSuggestion(@NonNull PhoneTimeZoneSuggestion suggestion) {
-        int score;
-        if (suggestion.getZoneId() == null || !isValid(suggestion)) {
-            score = SCORE_NONE;
-        } else if (suggestion.getMatchType() == TEST_NETWORK_OFFSET_ONLY
-                || suggestion.getMatchType() == EMULATOR_ZONE_ID) {
-            // Handle emulator / test cases : These suggestions should always just be used.
-            score = SCORE_HIGHEST;
-        } else if (suggestion.getQuality() == SINGLE_ZONE) {
-            score = SCORE_HIGH;
-        } else if (suggestion.getQuality() == MULTIPLE_ZONES_WITH_SAME_OFFSET) {
-            // The suggestion may be wrong, but at least the offset should be correct.
-            score = SCORE_MEDIUM;
-        } else if (suggestion.getQuality() == MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS) {
-            // The suggestion has a good chance of being wrong.
-            score = SCORE_LOW;
-        } else {
-            throw new AssertionError();
-        }
-        return score;
-    }
-
-    private static boolean isValid(@NonNull PhoneTimeZoneSuggestion suggestion) {
-        int quality = suggestion.getQuality();
-        int matchType = suggestion.getMatchType();
-        if (suggestion.getZoneId() == null) {
-            return quality == QUALITY_NA && matchType == MATCH_TYPE_NA;
-        } else {
-            boolean qualityValid = quality == SINGLE_ZONE
-                    || quality == MULTIPLE_ZONES_WITH_SAME_OFFSET
-                    || quality == MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-            boolean matchTypeValid = matchType == NETWORK_COUNTRY_ONLY
-                    || matchType == NETWORK_COUNTRY_AND_OFFSET
-                    || matchType == EMULATOR_ZONE_ID
-                    || matchType == TEST_NETWORK_OFFSET_ONLY;
-            return qualityValid && matchTypeValid;
-        }
-    }
-
-    /**
-     * Finds the best available time zone suggestion from all phones. If it is high-enough quality
-     * and automatic time zone detection is enabled then it will be set on the device. The outcome
-     * can be that this service becomes / remains un-opinionated and nothing is set.
-     */
-    @GuardedBy("this")
-    private void doTimeZoneDetection() {
-        QualifiedPhoneTimeZoneSuggestion bestSuggestion = findBestSuggestion();
-        boolean timeZoneDetectionEnabled =
-                mTimeZoneDetectionServiceHelper.isTimeZoneDetectionEnabled();
-
-        // Work out what to do with the best suggestion.
-        if (bestSuggestion == null) {
-            // There is no suggestion. Become un-opinionated.
-            if (DBG) {
-                Log.d(LOG_TAG, "doTimeZoneDetection: No good suggestion."
-                        + " bestSuggestion=null"
-                        + ", timeZoneDetectionEnabled=" + timeZoneDetectionEnabled);
-            }
-            mCurrentSuggestion = null;
-            return;
-        }
-
-        // Special case handling for uninitialized devices. This should only happen once.
-        String newZoneId = bestSuggestion.suggestion.getZoneId();
-        if (newZoneId != null && !mTimeZoneDetectionServiceHelper.isTimeZoneSettingInitialized()) {
-            Log.i(LOG_TAG, "doTimeZoneDetection: Device has no time zone set so might set the"
-                    + " device to the best available suggestion."
-                    + " bestSuggestion=" + bestSuggestion
-                    + ", timeZoneDetectionEnabled=" + timeZoneDetectionEnabled);
-
-            mCurrentSuggestion = bestSuggestion;
-            if (timeZoneDetectionEnabled) {
-                mTimeZoneDetectionServiceHelper.setDeviceTimeZoneFromSuggestion(
-                        bestSuggestion.suggestion);
-            }
-            return;
-        }
-
-        boolean suggestionGoodEnough = bestSuggestion.score >= SCORE_USAGE_THRESHOLD;
-        if (!suggestionGoodEnough) {
-            if (DBG) {
-                Log.d(LOG_TAG, "doTimeZoneDetection: Suggestion not good enough."
-                        + " bestSuggestion=" + bestSuggestion);
-            }
-            mCurrentSuggestion = null;
-            return;
-        }
-
-        // Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time
-        // zone ID.
-        if (newZoneId == null) {
-            Log.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
-                    + " bestSuggestion=" + bestSuggestion);
-            mCurrentSuggestion = null;
-            return;
-        }
-
-        // There is a good suggestion. Store the suggestion and set the device time zone if
-        // settings allow.
-        mCurrentSuggestion = bestSuggestion;
-
-        // Only set the device time zone if time zone detection is enabled.
-        if (!timeZoneDetectionEnabled) {
-            if (DBG) {
-                Log.d(LOG_TAG, "doTimeZoneDetection: Not setting the time zone because time zone"
-                        + " detection is disabled."
-                        + " bestSuggestion=" + bestSuggestion);
-            }
-            return;
-        }
-        mTimeZoneDetectionServiceHelper.setDeviceTimeZoneFromSuggestion(bestSuggestion.suggestion);
-    }
-
-    @GuardedBy("this")
-    @Nullable
-    private QualifiedPhoneTimeZoneSuggestion findBestSuggestion() {
-        QualifiedPhoneTimeZoneSuggestion bestSuggestion = null;
-
-        // Iterate over the latest QualifiedPhoneTimeZoneSuggestion objects received for each phone
-        // and find the best. Note that we deliberately do not look at age: the caller can
-        // rate-limit so age is not a strong indicator of confidence. Instead, the callers are
-        // expected to withdraw suggestions they no longer have confidence in.
-        for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
-            LinkedList<QualifiedPhoneTimeZoneSuggestion> phoneSuggestions =
-                    mSuggestionByPhoneId.valueAt(i);
-            if (phoneSuggestions == null) {
-                // Unexpected
-                continue;
-            }
-            QualifiedPhoneTimeZoneSuggestion candidateSuggestion = phoneSuggestions.getFirst();
-            if (candidateSuggestion == null) {
-                // Unexpected
-                continue;
-            }
-
-            if (bestSuggestion == null) {
-                bestSuggestion = candidateSuggestion;
-            } else if (candidateSuggestion.score > bestSuggestion.score) {
-                bestSuggestion = candidateSuggestion;
-            } else if (candidateSuggestion.score == bestSuggestion.score) {
-                // Tie! Use the suggestion with the lowest phoneId.
-                int candidatePhoneId = candidateSuggestion.suggestion.getPhoneId();
-                int bestPhoneId = bestSuggestion.suggestion.getPhoneId();
-                if (candidatePhoneId < bestPhoneId) {
-                    bestSuggestion = candidateSuggestion;
-                }
-            }
-        }
-        return bestSuggestion;
-    }
-
-    /**
-     * Returns the current best suggestion. Not intended for general use: it is used during tests
-     * to check service behavior.
-     */
-    @VisibleForTesting
-    @Nullable
-    public synchronized QualifiedPhoneTimeZoneSuggestion findBestSuggestionForTests() {
-        return findBestSuggestion();
-    }
-
-    private synchronized void handleAutoTimeZoneEnabled() {
-        if (DBG) {
-            Log.d(LOG_TAG, "handleAutoTimeEnabled() called");
-        }
-        // When the user enabled time zone detection, run the time zone detection and change the
-        // device time zone if possible.
-        doTimeZoneDetection();
-    }
-
-    /**
-     * Dumps any logs held to the supplied writer.
-     */
-    public void dumpLogs(IndentingPrintWriter ipw) {
-        mTimeZoneDetectionServiceHelper.dumpLogs(ipw);
-    }
-
-    /**
-     * Dumps internal state such as field values.
-     */
-    public void dumpState(PrintWriter pw) {
-        pw.println(" TimeZoneDetectionService.mCurrentSuggestion=" + mCurrentSuggestion);
-        pw.println(" TimeZoneDetectionService.mSuggestionsByPhoneId=" + mSuggestionByPhoneId);
-        mTimeZoneDetectionServiceHelper.dumpState(pw);
-        pw.flush();
-    }
-
-    /**
-     * A method used to inspect service state during tests. Not intended for general use.
-     */
-    @VisibleForTesting
-    public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int phoneId) {
-        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
-                mSuggestionByPhoneId.get(phoneId);
-        if (suggestions == null) {
-            return null;
-        }
-        return suggestions.getFirst();
-    }
-
-    /**
-     * A {@link PhoneTimeZoneSuggestion} with additional qualifying metadata.
-     */
-    @VisibleForTesting
-    public static class QualifiedPhoneTimeZoneSuggestion {
-
-        @VisibleForTesting
-        public final PhoneTimeZoneSuggestion suggestion;
-
-        /**
-         * The score the suggestion has been given. This can be used to rank against other
-         * suggestions of the same type.
-         */
-        @VisibleForTesting
-        public final int score;
-
-        @VisibleForTesting
-        public QualifiedPhoneTimeZoneSuggestion(PhoneTimeZoneSuggestion suggestion, int score) {
-            this.suggestion = suggestion;
-            this.score = score;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-            QualifiedPhoneTimeZoneSuggestion that = (QualifiedPhoneTimeZoneSuggestion) o;
-            return score == that.score
-                    && suggestion.equals(that.suggestion);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(score, suggestion);
-        }
-
-        @Override
-        public String toString() {
-            return "QualifiedPhoneTimeZoneSuggestion{"
-                    + "suggestion=" + suggestion
-                    + ", score=" + score
-                    + '}';
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceHelperImpl.java b/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceHelperImpl.java
deleted file mode 100644
index fc857a7..0000000
--- a/src/java/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceHelperImpl.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2017 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.nitz.service;
-
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.LocalLog;
-import android.util.Log;
-
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.PrintWriter;
-
-/**
- * The real implementation of {@link TimeZoneDetectionService.Helper}.
- */
-public final class TimeZoneDetectionServiceHelperImpl implements TimeZoneDetectionService.Helper {
-
-    private static final String LOG_TAG = TimeZoneDetectionService.LOG_TAG;
-    private static final boolean DBG = TimeZoneDetectionService.DBG;
-    private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
-
-    private final Context mContext;
-    private final ContentResolver mCr;
-    private final LocalLog mTimeZoneLog = new LocalLog(30);
-
-    private Listener mListener;
-
-    /** Creates a TimeServiceHelper */
-    public TimeZoneDetectionServiceHelperImpl(Context context) {
-        mContext = context;
-        mCr = context.getContentResolver();
-    }
-
-    @Override
-    public void setListener(Listener listener) {
-        if (listener == null) {
-            throw new NullPointerException("listener==null");
-        }
-        if (mListener != null) {
-            throw new IllegalStateException("listener already set");
-        }
-        this.mListener = listener;
-        mCr.registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
-                new ContentObserver(new Handler()) {
-                    public void onChange(boolean selfChange) {
-                        listener.onTimeZoneDetectionChange(isTimeZoneDetectionEnabled());
-                    }
-                });
-    }
-
-    @Override
-    public boolean isTimeZoneDetectionEnabled() {
-        try {
-            return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0;
-        } catch (Settings.SettingNotFoundException snfe) {
-            return true;
-        }
-    }
-
-    @Override
-    public boolean isTimeZoneSettingInitialized() {
-        // timezone.equals("GMT") will be true and only true if the time zone was
-        // set to a default value by the system server (when starting, system server
-        // sets the persist.sys.timezone to "GMT" if it's not set). "GMT" is not used by
-        // any code that sets it explicitly (in case where something sets GMT explicitly,
-        // "Etc/GMT" Olson ID would be used).
-
-        String timeZoneId = getTimeZoneSetting();
-        return timeZoneId != null && timeZoneId.length() > 0 && !timeZoneId.equals("GMT");
-    }
-
-    @Override
-    public void setDeviceTimeZoneFromSuggestion(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-        String currentZoneId = getTimeZoneSetting();
-        String newZoneId = timeZoneSuggestion.getZoneId();
-        if (newZoneId.equals(currentZoneId)) {
-            // No need to set the device time zone - the setting is already what we would be
-            // suggesting.
-            if (DBG) {
-                Log.d(LOG_TAG, "setDeviceTimeZoneAsNeeded: No need to change the time zone;"
-                        + " device is already set to the suggested zone."
-                        + " timeZoneSuggestion=" + timeZoneSuggestion);
-            }
-            return;
-        }
-
-        String msg = "Changing device time zone. currentZoneId=" + currentZoneId
-                + ", timeZoneSuggestion=" + timeZoneSuggestion;
-        if (DBG) {
-            Log.d(LOG_TAG, msg);
-        }
-        mTimeZoneLog.log(msg);
-
-        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        alarmManager.setTimeZone(newZoneId);
-        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra("time-zone", newZoneId);
-        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    @Nullable
-    private String getTimeZoneSetting() {
-        return SystemProperties.get(TIMEZONE_PROPERTY);
-    }
-
-    @Override
-    public void dumpState(PrintWriter pw) {
-        pw.println(" TimeZoneDetectionServiceHelperImpl.getTimeZoneSetting()="
-                + getTimeZoneSetting());
-    }
-
-    @Override
-    public void dumpLogs(IndentingPrintWriter ipw) {
-        ipw.println("TimeZoneDetectionServiceHelperImpl:");
-
-        ipw.increaseIndent();
-        ipw.println("Time zone logs:");
-        ipw.increaseIndent();
-        mTimeZoneLog.dump(ipw);
-        ipw.decreaseIndent();
-
-        ipw.decreaseIndent();
-    }
-}
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index d904caf..b63aa3e 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.data.DataProfile;
 import android.telephony.emergency.EmergencyNumber;
 
@@ -241,6 +242,10 @@
     }
 
     @Override
+    public void sendCdmaSMSExpectMore(byte[] pdu, Message result) {
+    }
+
+    @Override
     public void sendImsGsmSms (String smscPDU, String pdu,
             int retry, int messageRef, Message response) {
     }
@@ -334,8 +339,7 @@
     }
 
     @Override
-    public void setNetworkSelectionModeManual(
-            String operatorNumeric, Message response) {
+    public void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message response) {
     }
 
     @Override
@@ -635,8 +639,8 @@
     }
 
     @Override
-    public void setSignalStrengthReportingCriteria(int hysteresisMs, int hysteresisDb,
-            int[] thresholdsDbm, int ran, Message result) {
+    public void setSignalStrengthReportingCriteria(
+            SignalThresholdInfo signalThresholdInfo, int ran, Message result) {
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/sip/SipConnectionBase.java b/src/java/com/android/internal/telephony/sip/SipConnectionBase.java
index acf6d36..40e5203 100644
--- a/src/java/com/android/internal/telephony/sip/SipConnectionBase.java
+++ b/src/java/com/android/internal/telephony/sip/SipConnectionBase.java
@@ -16,16 +16,15 @@
 
 package com.android.internal.telephony.sip;
 
+import android.os.SystemClock;
+import android.telephony.PhoneNumberUtils;
+
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.UUSInfo;
-
-import android.os.SystemClock;
-import android.telephony.DisconnectCause;
-import android.telephony.Rlog;
-import android.telephony.PhoneNumberUtils;
+import com.android.telephony.Rlog;
 
 abstract class SipConnectionBase extends Connection {
     private static final String LOG_TAG = "SipConnBase";
diff --git a/src/java/com/android/internal/telephony/sip/SipPhone.java b/src/java/com/android/internal/telephony/sip/SipPhone.java
index 7fcaf96..ea7aa3e 100644
--- a/src/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhone.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.sip;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.media.AudioManager;
 import android.net.rtp.AudioGroup;
@@ -29,7 +30,6 @@
 import android.os.Message;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.text.TextUtils;
 
@@ -39,8 +39,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneNotifier;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import com.android.telephony.Rlog;
 
 import java.text.ParseException;
 import java.util.List;
@@ -187,6 +186,12 @@
     }
 
     @Override
+    public Connection startConference(String[] participantsToDial, DialArgs dialArgs)
+            throws CallStateException {
+        throw new CallStateException("startConference: not supported");
+    }
+
+    @Override
     public Connection dial(String dialString, DialArgs dialArgs) throws CallStateException {
         synchronized (SipPhone.class) {
             return dialInternal(dialString, dialArgs.videoState);
@@ -544,6 +549,16 @@
             }
         }
 
+        /**
+         * Hangup the ringing call with a specified reason; reason is not supported on SIP.
+         * @param rejectReason
+         */
+        @Override
+        public void hangup(@android.telecom.Call.RejectReason int rejectReason)
+                throws CallStateException  {
+            hangup();
+        }
+
         SipConnection initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) {
             SipProfile callee = sipAudioCall.getPeerProfile();
             SipConnection c = new SipConnection(this, callee);
diff --git a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
index a87fb2b..75aa1e4 100755
--- a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -23,9 +23,8 @@
 import android.os.Message;
 import android.os.RegistrantList;
 import android.os.ResultReceiver;
-import android.os.SystemProperties;
+import android.sysprop.TelephonyProperties;
 import android.telephony.NetworkScanRequest;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 
@@ -38,8 +37,8 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneNotifier;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.uicc.IccFileHandler;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -186,10 +185,9 @@
         Rlog.v(LOG_TAG, "canDial(): serviceState = " + serviceState);
         if (serviceState == ServiceState.STATE_POWER_OFF) return false;
 
-        String disableCall = SystemProperties.get(
-                TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
+        boolean disableCall = TelephonyProperties.disable_call().orElse(false);
         Rlog.v(LOG_TAG, "canDial(): disableCall = " + disableCall);
-        if (disableCall.equals("true")) return false;
+        if (disableCall) return false;
 
         Rlog.v(LOG_TAG, "canDial(): ringingCall: " + getRingingCall().getState());
         Rlog.v(LOG_TAG, "canDial(): foregndCall: " + getForegroundCall().getState());
diff --git a/src/java/com/android/internal/telephony/sip/SipPhoneFactory.java b/src/java/com/android/internal/telephony/sip/SipPhoneFactory.java
index 3383bed..42b7be7 100644
--- a/src/java/com/android/internal/telephony/sip/SipPhoneFactory.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhoneFactory.java
@@ -16,11 +16,11 @@
 
 package com.android.internal.telephony.sip;
 
-import com.android.internal.telephony.PhoneNotifier;
-
 import android.content.Context;
 import android.net.sip.SipProfile;
-import android.telephony.Rlog;
+
+import com.android.internal.telephony.PhoneNotifier;
+import com.android.telephony.Rlog;
 
 import java.text.ParseException;
 
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/AdnRecord.java b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
index 7aa6a11..8ab7722 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnRecord.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
@@ -16,18 +16,17 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.GsmAlphabet;
+import com.android.telephony.Rlog;
 
 import java.util.Arrays;
 
-
 /**
  *
  * Used to load or store ADNs (Abbreviated Dialing Numbers).
@@ -93,9 +92,14 @@
             recordNumber = source.readInt();
             alphaTag = source.readString();
             number = source.readString();
-            emails = source.readStringArray();
-
-            return new AdnRecord(efid, recordNumber, alphaTag, number, emails);
+            final int len = source.readInt();
+            if (len > 0) {
+                emails = new String[len];
+                source.readStringArray(emails);
+                return new AdnRecord(efid, recordNumber, alphaTag, number, emails);
+            } else {
+                return new AdnRecord(efid, recordNumber, alphaTag, number, null);
+            }
         }
 
         @Override
diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java b/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java
index 959984b..90d7a38 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java b/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java
index 391b8fc..a23248c 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java
@@ -16,16 +16,15 @@
 
 package com.android.internal.telephony.uicc;
 
-import java.util.ArrayList;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.Rlog;
 
-import com.android.internal.telephony.uicc.IccConstants;
+import com.android.telephony.Rlog;
+
+import java.util.ArrayList;
 
 public class AdnRecordLoader extends Handler {
     final static String LOG_TAG = "AdnRecordLoader";
diff --git a/src/java/com/android/internal/telephony/uicc/AnswerToReset.java b/src/java/com/android/internal/telephony/uicc/AnswerToReset.java
index 6fd7c68..9ded7d6 100644
--- a/src/java/com/android/internal/telephony/uicc/AnswerToReset.java
+++ b/src/java/com/android/internal/telephony/uicc/AnswerToReset.java
@@ -17,10 +17,10 @@
 package com.android.internal.telephony.uicc;
 
 import android.annotation.Nullable;
-import android.telephony.Rlog;
 import android.util.ArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java b/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
index 61379d2..da51848 100644
--- a/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
+++ b/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
@@ -17,10 +17,10 @@
 package com.android.internal.telephony.uicc;
 
 import android.os.Environment;
-import android.telephony.Rlog;
 import android.util.Xml;
 
-import com.android.internal.util.XmlUtils;
+import com.android.internal.telephony.util.XmlUtils;
+import com.android.telephony.Rlog;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/src/java/com/android/internal/telephony/uicc/CsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/CsimFileHandler.java
index e45afa9..c5dd05c 100644
--- a/src/java/com/android/internal/telephony/uicc/CsimFileHandler.java
+++ b/src/java/com/android/internal/telephony/uicc/CsimFileHandler.java
@@ -16,9 +16,8 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.telephony.Rlog;
-
 import com.android.internal.telephony.CommandsInterface;
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java b/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java
index 87bbc69..a47cc00 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java
@@ -16,11 +16,10 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
-
+import com.android.telephony.Rlog;
 
 /**
  * See also RIL_AppStatus in include/telephony/ril.h
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java
index df21601..765d1e1 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.telephony.SubscriptionInfo;
 
 /**
diff --git a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java
index 6d5232b..ceeed34 100644
--- a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java
+++ b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java
@@ -16,8 +16,10 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
-import android.os.*;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
 
 import com.android.internal.telephony.CommandsInterface;
 
diff --git a/src/java/com/android/internal/telephony/uicc/IccIoResult.java b/src/java/com/android/internal/telephony/uicc/IccIoResult.java
index d23f8a0..c3fdf1f 100644
--- a/src/java/com/android/internal/telephony/uicc/IccIoResult.java
+++ b/src/java/com/android/internal/telephony/uicc/IccIoResult.java
@@ -16,8 +16,9 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
+import android.compat.annotation.UnsupportedAppUsage;
+
+import com.android.internal.telephony.util.TelephonyUtils;
 
 /**
  * {@hide}
@@ -201,7 +202,7 @@
                 + " sw2:0x"
                 + Integer.toHexString(sw2)
                 + " Payload: "
-                + (Build.IS_DEBUGGABLE ? IccUtils.bytesToHexString(payload) : "*******")
+                + (TelephonyUtils.IS_DEBUGGABLE ? IccUtils.bytesToHexString(payload) : "*******")
                 + ((!success()) ? " Error: " + getErrorString() : "");
     }
 
diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java
index f3c8afe..139fffb 100644
--- a/src/java/com/android/internal/telephony/uicc/IccRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java
@@ -17,14 +17,14 @@
 package com.android.internal.telephony.uicc;
 
 import android.annotation.IntDef;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Registrant;
 import android.os.RegistrantList;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -32,7 +32,8 @@
 
 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 com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -144,6 +145,8 @@
     protected int mMncLength = UNINITIALIZED;
     protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
 
+    protected int mSmsCountOnIcc = 0;
+
     @UnsupportedAppUsage
     private String mSpn;
 
@@ -214,6 +217,7 @@
     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
     public static final int EVENT_REFRESH = 31; // ICC refresh occurred
     private static final int EVENT_AKA_AUTHENTICATE_DONE          = 90;
+    protected static final int EVENT_GET_SMS_RECORD_SIZE_DONE = 28;
 
     protected static final int SYSTEM_EVENT_BASE = 0x100;
     protected static final int EVENT_APP_READY = 1 + SYSTEM_EVENT_BASE;
@@ -742,6 +746,23 @@
         return mSpn;
     }
 
+    /**
+     * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41) or
+     * the brand override. The brand override has higher priority than the SPN from SIM.
+     *
+     * @return service provider name.
+     */
+    @Nullable
+    public String getServiceProviderNameWithBrandOverride() {
+        if (mParentApp != null && mParentApp.getUiccProfile() != null) {
+            String brandOverride = mParentApp.getUiccProfile().getOperatorBrandOverride();
+            if (!TextUtils.isEmpty(brandOverride)) {
+                return brandOverride;
+            }
+        }
+        return mSpn;
+    }
+
     protected void setServiceProviderName(String spn) {
         if (!TextUtils.equals(mSpn, spn)) {
             mSpn = spn != null ? spn.trim() : null;
@@ -887,6 +908,33 @@
 
                 break;
 
+            case EVENT_GET_SMS_RECORD_SIZE_DONE:
+                ar = (AsyncResult) msg.obj;
+
+                if (ar.exception != null) {
+                    onRecordLoaded();
+                    loge("Exception in EVENT_GET_SMS_RECORD_SIZE_DONE " + ar.exception);
+                    break;
+                }
+
+                int[] recordSize = (int[])ar.result;
+                try {
+                    // recordSize[0]  is the record length
+                    // recordSize[1]  is the total length of the EF file
+                    // recordSize[2]  is the number of records in the EF file
+                    mSmsCountOnIcc = recordSize[2];
+                    log("EVENT_GET_SMS_RECORD_SIZE_DONE Size " + recordSize[0]
+                            + " total " + recordSize[1]
+                                    + " record " + recordSize[2]);
+                } catch (ArrayIndexOutOfBoundsException exc) {
+                    mSmsCountOnIcc = -1;
+                    loge("ArrayIndexOutOfBoundsException in EVENT_GET_SMS_RECORD_SIZE_DONE: "
+                            + exc.toString());
+                } finally {
+                    onRecordLoaded();
+                }
+                break;
+
             default:
                 super.handleMessage(msg);
         }
@@ -1133,12 +1181,6 @@
         return null;
     }
 
-    protected void setSystemProperty(String key, String val) {
-        TelephonyManager.getDefault().setTelephonyProperty(mParentApp.getPhoneId(), key, val);
-
-        log("[key, value]=" + key + ", " +  val);
-    }
-
     /**
      * Returns the response of the SIM application on the UICC to authentication
      * challenge/response algorithm. The data string and challenge response are
@@ -1228,6 +1270,14 @@
         return carrierNameDisplayCondition;
     }
 
+    /**
+     * Get SMS capacity count on ICC card.
+     */
+    public int getSmsCapacityOnIcc() {
+        if (DBG) log("getSmsCapacityOnIcc: " + mSmsCountOnIcc);
+        return mSmsCountOnIcc;
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("IccRecords: " + this);
         pw.println(" mDestroyed=" + mDestroyed);
diff --git a/src/java/com/android/internal/telephony/uicc/IccRefreshResponse.java b/src/java/com/android/internal/telephony/uicc/IccRefreshResponse.java
index ccb6f98..a02e6a2 100644
--- a/src/java/com/android/internal/telephony/uicc/IccRefreshResponse.java
+++ b/src/java/com/android/internal/telephony/uicc/IccRefreshResponse.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * See also RIL_SimRefresh in include/telephony/ril.h
diff --git a/src/java/com/android/internal/telephony/uicc/IccServiceTable.java b/src/java/com/android/internal/telephony/uicc/IccServiceTable.java
index b2e2f27..fe6e433 100644
--- a/src/java/com/android/internal/telephony/uicc/IccServiceTable.java
+++ b/src/java/com/android/internal/telephony/uicc/IccServiceTable.java
@@ -16,8 +16,9 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.Rlog;
+import android.compat.annotation.UnsupportedAppUsage;
+
+import com.android.telephony.Rlog;
 
 /**
  * Wrapper class for an ICC EF containing a bit field of enabled services.
diff --git a/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java
index 6fe16c9..fe900cb 100644
--- a/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java
+++ b/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java
@@ -16,9 +16,8 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.telephony.Rlog;
-
 import com.android.internal.telephony.CommandsInterface;
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/uicc/IsimRecords.java b/src/java/com/android/internal/telephony/uicc/IsimRecords.java
index 65cfd6f..3de7b3d 100644
--- a/src/java/com/android/internal/telephony/uicc/IsimRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IsimRecords.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java
index 5630a01..460afc7 100644
--- a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java
@@ -16,16 +16,16 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncResult;
 import android.os.Message;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.gsm.SimTlv;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -435,12 +435,20 @@
     @UnsupportedAppUsage
     @Override
     protected void log(String s) {
-        if (DBG) Rlog.d(LOG_TAG, "[ISIM] " + s);
+        if (mParentApp != null) {
+            Rlog.d(LOG_TAG, "[ISIM-" + mParentApp.getPhoneId() + "] " + s);
+        } else {
+            Rlog.d(LOG_TAG, "[ISIM] " + s);
+        }
     }
 
     @Override
     protected void loge(String s) {
-        if (DBG) Rlog.e(LOG_TAG, "[ISIM] " + s);
+        if (mParentApp != null) {
+            Rlog.e(LOG_TAG, "[ISIM-" + mParentApp.getPhoneId() + "] " + s);
+        } else {
+            Rlog.e(LOG_TAG, "[ISIM] " + s);
+        }
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java b/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java
index 4d0b484..61352d9 100755
--- a/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java
+++ b/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java
@@ -19,7 +19,8 @@
 import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Rlog;
+
+import com.android.telephony.Rlog;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/src/java/com/android/internal/telephony/uicc/RuimFileHandler.java b/src/java/com/android/internal/telephony/uicc/RuimFileHandler.java
index 58e939f..2323b5a 100644
--- a/src/java/com/android/internal/telephony/uicc/RuimFileHandler.java
+++ b/src/java/com/android/internal/telephony/uicc/RuimFileHandler.java
@@ -17,9 +17,9 @@
 package com.android.internal.telephony.uicc;
 
 import android.os.*;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.CommandsInterface;
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
index 0210ec0..28ce2d2 100644
--- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
@@ -16,15 +16,12 @@
 
 package com.android.internal.telephony.uicc;
 
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.AsyncResult;
 import android.os.Message;
-import android.os.SystemProperties;
-import android.telephony.Rlog;
+import android.sysprop.TelephonyProperties;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
@@ -37,6 +34,7 @@
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.util.BitwiseInputStream;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -326,7 +324,7 @@
                     // SPN is checked to have characters in printable ASCII
                     // range. If not, they are decoded with
                     // ENCODING_GSM_7BIT_ALPHABET scheme.
-                    if (TextUtils.isPrintableAsciiOnly(spn)) {
+                    if (isPrintableAsciiOnly(spn)) {
                         setServiceProviderName(spn);
                     } else {
                         if (DBG) log("Some corruption in SPN decoding = " + spn);
@@ -351,6 +349,22 @@
         }
     }
 
+    private static boolean isPrintableAsciiOnly(final CharSequence str) {
+        final int len = str.length();
+        for (int i = 0; i < len; i++) {
+            if (!isPrintableAscii(str.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isPrintableAscii(final char c) {
+        final int asciiFirst = 0x20;
+        final int asciiLast = 0x7E;  // included
+        return (asciiFirst <= c && c <= asciiLast) || c == '\r' || c == '\n';
+    }
+
     private class EfCsimMdnLoaded implements IccRecordLoaded {
         @Override
         public String getEfName() {
@@ -875,6 +889,8 @@
         mFh.loadEFTransparent(EF_CSIM_MIPUPP,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMipUppLoaded()));
         mRecordsToLoad++;
+        mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE));
+        mRecordsToLoad++;
 
         if (DBG) log("fetchRuimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
         // Further records that can be inserted are Operator/OEM dependent
@@ -886,9 +902,9 @@
         // to determine if the SIM is provisioned.  Otherwise,
         // consider the SIM is provisioned. (for case of ordinal
         // USIM only UICC.)
-        // If PROPERTY_TEST_CSIM is defined, bypess provision check
-        // and consider the SIM is provisioned.
-        if (SystemProperties.getBoolean(PROPERTY_TEST_CSIM, false)) {
+        // If test_csim is true, bypess provision check and
+        // consider the SIM is provisioned.
+        if (TelephonyProperties.test_csim().orElse(false)) {
             return true;
         }
 
@@ -949,13 +965,21 @@
     @UnsupportedAppUsage
     @Override
     protected void log(String s) {
-        Rlog.d(LOG_TAG, "[RuimRecords] " + s);
+        if (mParentApp != null) {
+            Rlog.d(LOG_TAG, "[RuimRecords-" + mParentApp.getPhoneId() + "] " + s);
+        } else {
+            Rlog.d(LOG_TAG, "[RuimRecords] " + s);
+        }
     }
 
     @UnsupportedAppUsage
     @Override
     protected void loge(String s) {
-        Rlog.e(LOG_TAG, "[RuimRecords] " + s);
+        if (mParentApp != null) {
+            Rlog.e(LOG_TAG, "[RuimRecords-" + mParentApp.getPhoneId() + "] " + s);
+        } else {
+            Rlog.e(LOG_TAG, "[RuimRecords] " + s);
+        }
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java b/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java
index 3be0c99..be165c1 100644
--- a/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java
@@ -16,9 +16,8 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.telephony.Rlog;
-
 import com.android.internal.telephony.CommandsInterface;
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
index cde7f22..1118045 100644
--- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
@@ -16,7 +16,10 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import static android.telephony.SmsManager.STATUS_ON_ICC_READ;
+import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
+
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.AsyncResult;
@@ -24,7 +27,6 @@
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 import android.telephony.SmsMessage;
 import android.telephony.SubscriptionInfo;
 import android.text.TextUtils;
@@ -36,6 +38,7 @@
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.gsm.SimTlv;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -929,7 +932,7 @@
                     break;
 
                 case EVENT_MARK_SMS_READ_DONE:
-                    Rlog.i("ENF", "marked read: sms " + msg.arg1);
+                    log("marked read: sms " + msg.arg1);
                     break;
 
 
@@ -1356,21 +1359,18 @@
      * Dispatch 3GPP format message to registrant ({@code GsmCdmaPhone}) to pass to the 3GPP SMS
      * dispatcher for delivery.
      */
-    private int dispatchGsmMessage(SmsMessage message) {
+    private void dispatchGsmMessage(SmsMessage message) {
         mNewSmsRegistrants.notifyResult(message);
-        return 0;
     }
 
     private void handleSms(byte[] ba) {
-        if (ba[0] != 0)
-            Rlog.d("ENF", "status : " + ba[0]);
+        if (DBG) log("handleSms status : " + ba[0]);
 
-        // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
-        // 3 == "received by MS from network; message to be read"
-        if (ba[0] == 3) {
+        // ba[0] is status byte. (see 3GPP TS 51.011 10.5.3)
+        if ((ba[0] & 0x07) == STATUS_ON_ICC_UNREAD) {
             int n = ba.length;
 
-            // Note: Data may include trailing FF's.  That's OK; message
+            // Note: Data may include trailing FF's. That's OK; message
             // should still parse correctly.
             byte[] pdu = new byte[n - 1];
             System.arraycopy(ba, 1, pdu, 0, n - 1);
@@ -1380,23 +1380,19 @@
         }
     }
 
-
     private void handleSmses(ArrayList<byte[]> messages) {
         int count = messages.size();
 
         for (int i = 0; i < count; i++) {
             byte[] ba = messages.get(i);
 
-            if (ba[0] != 0)
-                Rlog.i("ENF", "status " + i + ": " + ba[0]);
+            if (DBG) log("handleSmses status " + i + ": " + ba[0]);
 
-            // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
-            // 3 == "received by MS from network; message to be read"
-
-            if (ba[0] == 3) {
+            // ba[0] is status byte. (see 3GPP TS 51.011 10.5.3)
+            if ((ba[0] & 0x07) == STATUS_ON_ICC_UNREAD) {
                 int n = ba.length;
 
-                // Note: Data may include trailing FF's.  That's OK; message
+                // Note: Data may include trailing FF's. That's OK; message
                 // should still parse correctly.
                 byte[] pdu = new byte[n - 1];
                 System.arraycopy(ba, 1, pdu, 0, n - 1);
@@ -1404,10 +1400,7 @@
 
                 dispatchGsmMessage(message);
 
-                // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
-                // 1 == "received by MS from network; message read"
-
-                ba[0] = 1;
+                ba[0] = (byte) STATUS_ON_ICC_READ;
 
                 if (false) { // FIXME: writing seems to crash RdoServD
                     mFh.updateEFLinearFixed(EF_SMS,
@@ -1660,6 +1653,8 @@
         mRecordsToLoad++;
 
         loadEfLiAndEfPl();
+        mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE));
+        mRecordsToLoad++;
 
         // XXX should seek instead of examining them all
         if (false) { // XXX
@@ -1925,22 +1920,38 @@
     @UnsupportedAppUsage
     @Override
     protected void log(String s) {
-        Rlog.d(LOG_TAG, "[SIMRecords] " + s);
+        if (mParentApp != null) {
+            Rlog.d(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s);
+        } else {
+            Rlog.d(LOG_TAG, "[SIMRecords] " + s);
+        }
     }
 
     @UnsupportedAppUsage
     @Override
     protected void loge(String s) {
-        Rlog.e(LOG_TAG, "[SIMRecords] " + s);
+        if (mParentApp != null) {
+            Rlog.e(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s);
+        } else {
+            Rlog.e(LOG_TAG, "[SIMRecords] " + s);
+        }
     }
 
     protected void logw(String s, Throwable tr) {
-        Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
+        if (mParentApp != null) {
+            Rlog.w(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s, tr);
+        } else {
+            Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
+        }
     }
 
     @UnsupportedAppUsage
     protected void logv(String s) {
-        Rlog.v(LOG_TAG, "[SIMRecords] " + s);
+        if (mParentApp != null) {
+            Rlog.v(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s);
+        } else {
+            Rlog.v(LOG_TAG, "[SIMRecords] " + s);
+        }
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java
index 985bfa8..73e26a9 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -24,7 +24,6 @@
 import android.content.pm.Signature;
 import android.os.Handler;
 import android.os.Message;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
@@ -33,6 +32,7 @@
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.uicc.IccCardStatus.CardState;
 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
index 0722394..83fbb65 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
@@ -16,14 +16,13 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Registrant;
 import android.os.RegistrantList;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.PhoneConstants;
@@ -31,6 +30,7 @@
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
index 0c4629b..e1bc0b7 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
@@ -17,7 +17,7 @@
 package com.android.internal.telephony.uicc;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -27,13 +27,13 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccAccessRule;
 import android.text.TextUtils;
 import android.util.LocalLog;
 
 import com.android.internal.telephony.CommandException;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -114,6 +114,8 @@
     // Max number of retries for open logical channel, interval is 10s.
     private static final int MAX_RETRY = 1;
     private static final int RETRY_INTERVAL_MS = 10000;
+    private static final int STATUS_CODE_CONDITION_NOT_SATISFIED = 0x6985;
+    private static final int STATUS_CODE_APPLET_SELECT_FAILED = 0x6999;
 
     // Used for parsing the data from the UICC.
     public static class TLV {
@@ -316,7 +318,7 @@
             // is disabled by default, and some other component wants to enable it when it has
             // gained carrier privileges (as an indication that a matching SIM has been inserted).
             PackageInfo pInfo = packageManager.getPackageInfo(packageName,
-                    PackageManager.GET_SIGNATURES
+                    PackageManager.GET_SIGNING_CERTIFICATES
                             | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
                             | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS);
             return getCarrierPrivilegeStatus(pInfo);
@@ -426,6 +428,30 @@
         return null;
     }
 
+    /**
+     * The following three situations could be due to logical channels temporarily unavailable, so
+     * we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS: 1. MISSING_RESOURCE,
+     * 2. NO_SUCH_ELEMENT and the status code is 6985, 3. INTERNAL_ERR and the status code is 6999.
+     */
+    public static boolean shouldRetry(AsyncResult ar, int retryCount) {
+        if (ar.exception instanceof CommandException && retryCount < MAX_RETRY) {
+            CommandException.Error error = ((CommandException) (ar.exception)).getCommandError();
+            int[] results = (int[]) ar.result;
+            int statusCode = 0;
+            if (ar.result != null && results.length == 3) {
+                byte[] bytes = new byte[]{(byte) results[1], (byte) results[2]};
+                statusCode = Integer.parseInt(IccUtils.bytesToHexString(bytes), 16);
+                log("status code: " + String.valueOf(statusCode));
+            }
+            return (error == CommandException.Error.MISSING_RESOURCE)
+                            || (error == CommandException.Error.NO_SUCH_ELEMENT
+                    && statusCode == STATUS_CODE_CONDITION_NOT_SATISFIED)
+                            || (error == CommandException.Error.INTERNAL_ERR
+                    && statusCode == STATUS_CODE_APPLET_SELECT_FAILED);
+        }
+        return false;
+    }
+
     @Override
     public void handleMessage(Message msg) {
         AsyncResult ar;
@@ -442,11 +468,8 @@
                             DATA, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, mChannelId,
                                     mAIDInUse));
                 } else {
-                    // MISSING_RESOURCE could be due to logical channels temporarily unavailable,
-                    // so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS.
-                    if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY
-                            && ((CommandException) (ar.exception)).getCommandError()
-                            == CommandException.Error.MISSING_RESOURCE) {
+                    if (shouldRetry(ar, mRetryCount)) {
+                        log("should retry");
                         mRetryCount++;
                         removeCallbacks(mRetryRunnable);
                         postDelayed(mRetryRunnable, RETRY_INTERVAL_MS);
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index 6112dda..a00a364 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -19,8 +19,10 @@
 import static android.telephony.TelephonyManager.UNINITIALIZED_CARD_ID;
 import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID;
 
-import android.annotation.UnsupportedAppUsage;
+import static java.util.Arrays.copyOf;
+
 import android.app.BroadcastOptions;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -33,7 +35,6 @@
 import android.os.storage.StorageManager;
 import android.preference.PreferenceManager;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccCardInfo;
 import android.text.TextUtils;
@@ -43,11 +44,13 @@
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.PhoneConfigurationManager;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.RadioConfig;
 import com.android.internal.telephony.SubscriptionInfoUpdater;
 import com.android.internal.telephony.uicc.euicc.EuiccCard;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -121,6 +124,7 @@
     private static final int EVENT_RADIO_UNAVAILABLE = 7;
     private static final int EVENT_SIM_REFRESH = 8;
     private static final int EVENT_EID_READY = 9;
+    private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10;
 
     // this needs to be here, because on bootup we dont know which index maps to which UiccSlot
     @UnsupportedAppUsage
@@ -187,20 +191,23 @@
     // LocalLog buffer to hold important SIM related events for debugging
     static LocalLog sLocalLog = new LocalLog(100);
 
-    public static UiccController make(Context c, CommandsInterface[] ci) {
+    /**
+     * API to make UiccController singleton if not already created.
+     */
+    public static UiccController make(Context c) {
         synchronized (mLock) {
             if (mInstance != null) {
                 throw new RuntimeException("UiccController.make() should only be called once");
             }
-            mInstance = new UiccController(c, ci);
+            mInstance = new UiccController(c);
             return mInstance;
         }
     }
 
-    private UiccController(Context c, CommandsInterface []ci) {
+    private UiccController(Context c) {
         if (DBG) log("Creating UiccController");
         mContext = c;
-        mCis = ci;
+        mCis = PhoneFactory.getCommandsInterfaces();
         if (DBG) {
             String logStr = "config_num_physical_slots = " + c.getResources().getInteger(
                     com.android.internal.R.integer.config_num_physical_slots);
@@ -216,7 +223,7 @@
         }
 
         mUiccSlots = new UiccSlot[numPhysicalSlots];
-        mPhoneIdToSlotId = new int[ci.length];
+        mPhoneIdToSlotId = new int[mCis.length];
         Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID);
         if (VDBG) logPhoneIdToSlotIdMapping();
         mRadioConfig = RadioConfig.getInstance(mContext);
@@ -245,6 +252,9 @@
         mEuiccSlots = mContext.getResources()
                 .getIntArray(com.android.internal.R.array.non_removable_euicc_slots);
         mHasBuiltInEuicc = hasBuiltInEuicc();
+
+        PhoneConfigurationManager.registerForMultiSimConfigChange(
+                this, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
     }
 
     /**
@@ -440,12 +450,11 @@
     @UnsupportedAppUsage
     public void registerForIccChanged(Handler h, int what, Object obj) {
         synchronized (mLock) {
-            Registrant r = new Registrant (h, what, obj);
-            mIccChangedRegistrants.add(r);
-            //Notify registrant right after registering, so that it will get the latest ICC status,
-            //otherwise which may not happen until there is an actual change in ICC status.
-            r.notifyRegistrant();
+            mIccChangedRegistrants.addUnique(h, what, obj);
         }
+        //Notify registrant right after registering, so that it will get the latest ICC status,
+        //otherwise which may not happen until there is an actual change in ICC status.
+        Message.obtain(h, what, new AsyncResult(obj, null, null)).sendToTarget();
     }
 
     public void unregisterForIccChanged(Handler h) {
@@ -519,6 +528,9 @@
                     if (DBG) log("Received EVENT_EID_READY");
                     onEidReady(ar, phoneId);
                     break;
+                case EVENT_MULTI_SIM_CONFIG_CHANGED:
+                    if (DBG) log("Received EVENT_MULTI_SIM_CONFIG_CHANGED");
+                    onMultiSimConfigChanged();
                 default:
                     Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
                     break;
@@ -526,6 +538,36 @@
         }
     }
 
+    private void onMultiSimConfigChanged() {
+        int prevActiveModemCount = mCis.length;
+        mCis = PhoneFactory.getCommandsInterfaces();
+
+        // Resize array.
+        mPhoneIdToSlotId = copyOf(mPhoneIdToSlotId, mCis.length);
+
+        // Register for new active modem for ss -> ds switch.
+        // For ds -> ss switch, there's no need to unregister as the mCis should unregister
+        // everything itself.
+        for (int i = prevActiveModemCount; i < mCis.length; i++) {
+            mPhoneIdToSlotId[i] = INVALID_SLOT_ID;
+            mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);
+
+            /*
+             * To support FDE (deprecated), additional check is needed:
+             *
+             * if (!StorageManager.inCryptKeeperBounce()) {
+             *     mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
+             * } else {
+             *     mCis[i].registerForOn(this, EVENT_RADIO_ON, i);
+             * }
+             */
+            mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
+
+            mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
+            mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
+        }
+    }
+
     private Integer getCiIndex(Message msg) {
         AsyncResult ar;
         Integer index = new Integer(PhoneConstants.DEFAULT_SLOT_INDEX);
@@ -654,17 +696,32 @@
             cardString = card.getIccId();
         }
 
-        // EID may be unpopulated if RadioConfig<1.2
-        // If so, just register for EID loaded and skip this stuff
-        if (isEuicc && cardString == null
-                && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) {
-            ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index);
-        }
-
         if (cardString != null) {
             addCardId(cardString);
         }
 
+        // EID is unpopulated if Radio HAL < 1.4 (RadioConfig < 1.2)
+        // If so, just register for EID loaded and skip this stuff
+        if (isEuicc && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) {
+            if (cardString == null) {
+                ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index);
+            } else {
+                // If we know the EID from IccCardStatus, just use it to set mDefaultEuiccCardId if
+                // it's not already set.
+                // This is needed in cases where slot status doesn't include EID, and we don't want
+                // to register for EID from APDU because we already know cardString from a previous
+                // APDU
+                if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
+                        || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
+                    mDefaultEuiccCardId = convertToPublicCardId(cardString);
+                    String logStr = "IccCardStatus eid=" + cardString + " slot=" + slotId
+                            + " mDefaultEuiccCardId=" + mDefaultEuiccCardId;
+                    sLocalLog.log(logStr);
+                    log(logStr);
+                }
+            }
+        }
+
         if (DBG) log("Notifying IccChangedRegistrants");
         mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
     }
diff --git a/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java b/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java
index cc99ae9..3513bb9 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java
@@ -19,9 +19,9 @@
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules.TLV;
+import com.android.telephony.Rlog;
 
 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..9ac21b0 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -38,7 +38,6 @@
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -62,6 +61,7 @@
 import com.android.internal.telephony.uicc.IccCardStatus.CardState;
 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
 import com.android.internal.telephony.uicc.euicc.EuiccCard;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -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;
+                }
             }
         }
 
@@ -436,7 +444,7 @@
             int nameSource) {
         /* update display name with carrier override */
         SubscriptionInfo subInfo = subCon.getActiveSubscriptionInfo(
-                subId, mContext.getOpPackageName());
+                subId, mContext.getOpPackageName(), null);
 
         if (subInfo == null) {
             return;
@@ -582,6 +590,12 @@
                 }
                 setExternalState(IccCardConstants.State.NOT_READY);
                 break;
+            case APPSTATE_DETECTED:
+                if (VDBG) {
+                    log("updateExternalState: app state is detected; setting state to NOT_READY");
+                }
+                setExternalState(IccCardConstants.State.NOT_READY);
+                break;
             case APPSTATE_READY:
                 checkAndUpdateIfAnyAppToBeIgnored();
                 if (areAllApplicationsReady()) {
diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
index 11478e6..db0aeb7 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
@@ -26,7 +26,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PowerManager;
-import android.telephony.Rlog;
+import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.view.WindowManager;
@@ -38,6 +38,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.uicc.IccCardStatus.CardState;
 import com.android.internal.telephony.uicc.euicc.EuiccCard;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -105,9 +106,9 @@
             //   2. The latest mCardState is not ABSENT, but there is no UiccCard instance.
             } else if ((oldState == null || oldState == CardState.CARDSTATE_ABSENT
                     || mUiccCard == null) && mCardState != CardState.CARDSTATE_ABSENT) {
-                // No notifications while radio is off or we just powering up
-                if (radioState == TelephonyManager.RADIO_POWER_ON
-                        && mLastRadioState == TelephonyManager.RADIO_POWER_ON) {
+                // No notification while we are just powering up
+                if (radioState != TelephonyManager.RADIO_POWER_UNAVAILABLE
+                        && mLastRadioState != TelephonyManager.RADIO_POWER_UNAVAILABLE) {
                     if (DBG) log("update: notify card added");
                     sendMessage(obtainMessage(EVENT_CARD_ADDED, null));
                 }
@@ -183,9 +184,9 @@
     private void updateCardStateAbsent() {
         int radioState =
                 (mCi == null) ? TelephonyManager.RADIO_POWER_UNAVAILABLE : mCi.getRadioState();
-        // No notifications while radio is off or we just powering up
-        if (radioState == TelephonyManager.RADIO_POWER_ON
-                && mLastRadioState == TelephonyManager.RADIO_POWER_ON) {
+        // No notification while we are just powering up
+        if (radioState != TelephonyManager.RADIO_POWER_UNAVAILABLE
+                && mLastRadioState != TelephonyManager.RADIO_POWER_UNAVAILABLE) {
             if (DBG) log("update: notify card removed");
             sendMessage(obtainMessage(EVENT_CARD_REMOVED, null));
         }
@@ -319,7 +320,7 @@
                         dialogComponent)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                         .putExtra(EXTRA_ICC_CARD_ADDED, isAdded);
                 try {
-                    mContext.startActivity(intent);
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                     return;
                 } catch (ActivityNotFoundException e) {
                     loge("Unable to find ICC hotswap prompt for restart activity: " + e);
diff --git a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java
index b120eb6..ff8d63d 100755
--- a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java
+++ b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java
@@ -16,10 +16,8 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.telephony.Rlog;
-
 import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.uicc.UiccCardApplication;
+import com.android.telephony.Rlog;
 
 /**
  * {@hide}
diff --git a/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java b/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java
index 2c103ca..281b5f2 100644
--- a/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java
+++ b/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 
 /**
diff --git a/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java b/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java
index b3bdf14..b10b875 100644
--- a/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java
+++ b/src/java/com/android/internal/telephony/uicc/VoiceMailConstants.java
@@ -16,21 +16,21 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Environment;
 import android.util.Xml;
-import android.telephony.Rlog;
 
-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 com.android.telephony.Rlog;
 
 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/uicc/euicc/EuiccCard.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
index 12f2ead..bff29ff 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
@@ -25,7 +25,6 @@
 import android.os.RegistrantList;
 import android.service.carrier.CarrierIdentifier;
 import android.service.euicc.EuiccProfileInfo;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.telephony.UiccAccessRule;
 import android.telephony.euicc.EuiccCardManager;
@@ -53,6 +52,7 @@
 import com.android.internal.telephony.uicc.euicc.apdu.RequestProvider;
 import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback;
 import com.android.internal.telephony.uicc.euicc.async.AsyncResultHelper;
+import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccSpecVersion.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccSpecVersion.java
index b038716..9450bfc 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccSpecVersion.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccSpecVersion.java
@@ -16,12 +16,11 @@
 
 package com.android.internal.telephony.uicc.euicc;
 
-import android.telephony.Rlog;
-
 import com.android.internal.telephony.uicc.asn1.Asn1Decoder;
 import com.android.internal.telephony.uicc.asn1.Asn1Node;
 import com.android.internal.telephony.uicc.asn1.InvalidAsn1DataException;
 import com.android.internal.telephony.uicc.asn1.TagNotFoundException;
+import com.android.telephony.Rlog;
 
 import java.util.Arrays;
 
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
index 1f72ae8..8e7237e 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
@@ -18,13 +18,14 @@
 
 import android.annotation.Nullable;
 import android.os.Handler;
+import android.os.Looper;
 import android.telephony.IccOpenLogicalChannelResponse;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback;
 import com.android.internal.telephony.uicc.euicc.async.AsyncResultHelper;
+import com.android.telephony.Rlog;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -50,10 +51,16 @@
     private static final int STATUS_NO_ERROR = 0x9000;
     private static final int SW1_NO_ERROR = 0x91;
 
+    private static final int WAIT_TIME_MS = 2000;
+
     private static void logv(String msg) {
         Rlog.v(LOG_TAG, msg);
     }
 
+    private static void logd(String msg) {
+        Rlog.d(LOG_TAG, msg);
+    }
+
     private final String mAid;
     private final boolean mSupportExtendedApdu;
     private final OpenLogicalChannelInvocation mOpenChannel;
@@ -94,10 +101,25 @@
             Handler handler) {
         synchronized (mChannelLock) {
             if (mChannelOpened) {
-                AsyncResultHelper.throwException(
-                        new ApduException("Logical channel has already been opened."),
-                        resultCallback, handler);
-                return;
+                if (!Looper.getMainLooper().equals(Looper.myLooper())) {
+                    logd("Logical channel has already been opened. Wait.");
+                    try {
+                        mChannelLock.wait(WAIT_TIME_MS);
+                    } catch (InterruptedException e) {
+                        // nothing to do
+                    }
+                    if (mChannelOpened) {
+                        AsyncResultHelper.throwException(
+                                new ApduException("The logical channel is still in use."),
+                                resultCallback, handler);
+                        return;
+                    }
+                } else {
+                    AsyncResultHelper.throwException(
+                            new ApduException("The logical channel is in use."),
+                            resultCallback, handler);
+                    return;
+                }
             }
             mChannelOpened = true;
         }
@@ -111,6 +133,7 @@
                         || status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR) {
                     synchronized (mChannelLock) {
                         mChannelOpened = false;
+                        mChannelLock.notify();
                     }
                     resultCallback.onException(
                             new ApduException("Failed to open logical channel opened for AID: "
@@ -245,6 +268,7 @@
             public void onResult(Boolean aBoolean) {
                 synchronized (mChannelLock) {
                     mChannelOpened = false;
+                    mChannelLock.notify();
                 }
 
                 if (exception == null) {
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java
index edd89d6..82ddb80 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java
@@ -18,11 +18,11 @@
 
 import android.os.AsyncResult;
 import android.os.Message;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.uicc.euicc.async.AsyncMessageInvocation;
+import com.android.telephony.Rlog;
 
 /**
  * Invokes {@link CommandsInterface#iccCloseLogicalChannel(int, Message)}. This takes a channel id
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/OpenLogicalChannelInvocation.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/OpenLogicalChannelInvocation.java
index 15b0c43..caed9cf 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/OpenLogicalChannelInvocation.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/OpenLogicalChannelInvocation.java
@@ -19,11 +19,11 @@
 import android.os.AsyncResult;
 import android.os.Message;
 import android.telephony.IccOpenLogicalChannelResponse;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.uicc.euicc.async.AsyncMessageInvocation;
+import com.android.telephony.Rlog;
 
 /**
  * Invokes {@link CommandsInterface#iccOpenLogicalChannel(String, int, Message)}. This takes AID
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java
index 296fe47..09de54a 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java
@@ -18,12 +18,12 @@
 
 import android.os.AsyncResult;
 import android.os.Message;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.euicc.async.AsyncMessageInvocation;
+import com.android.telephony.Rlog;
 
 /**
  * Invokes {@link CommandsInterface#iccTransmitApduLogicalChannel(int, int, int, int, int, int,
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java b/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java
index b28e7e7..58ab6bf 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony.uicc.euicc.async;
 
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 
 /**
  * Class to deliver the returned value from an asynchronous call. Either {@link #onResult(Result)}
diff --git a/src/java/com/android/internal/telephony/util/LocaleUtils.java b/src/java/com/android/internal/telephony/util/LocaleUtils.java
new file mode 100644
index 0000000..064b10d
--- /dev/null
+++ b/src/java/com/android/internal/telephony/util/LocaleUtils.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2019 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.util;
+
+import android.content.Context;
+import android.icu.util.ULocale;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.MccTable;
+import com.android.telephony.Rlog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * This class provides various util functions about Locale.
+ */
+public class LocaleUtils {
+
+    private static final String LOG_TAG = "LocaleUtils";
+
+    /**
+     * Get Locale based on the MCC of the SIM.
+     *
+     * @param context Context to act on.
+     * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
+     * @param simLanguage (nullable) the language from the SIM records (if present).
+     *
+     * @return locale for the mcc or null if none
+     */
+    public static Locale getLocaleFromMcc(Context context, int mcc, String simLanguage) {
+        boolean hasSimLanguage = !TextUtils.isEmpty(simLanguage);
+        String language = hasSimLanguage ? simLanguage : defaultLanguageForMcc(mcc);
+        String country = MccTable.countryCodeForMcc(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 = defaultLanguageForMcc(mcc);
+            Rlog.d(LOG_TAG, "[retry ] getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
+            return getLocaleForLanguageCountry(context, language, country);
+        }
+
+        return locale;
+    }
+
+    /**
+     * Return Locale for the language and country or null if no good match.
+     *
+     * @param context Context to act on.
+     * @param language Two character language code desired
+     * @param country Two character country code desired
+     *
+     * @return Locale or null if no appropriate value
+     */
+    private static Locale getLocaleForLanguageCountry(Context context, String language,
+                                                      String country) {
+        if (language == null) {
+            Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: skipping no language");
+            return null; // no match possible
+        }
+        if (country == null) {
+            country = ""; // The Locale constructor throws if passed null.
+        }
+
+        final Locale target = new Locale(language, country);
+        try {
+            String[] localeArray = context.getAssets().getLocales();
+            List<String> locales = new ArrayList<>(Arrays.asList(localeArray));
+
+            // Even in developer mode, you don't want the pseudolocales.
+            locales.remove("ar-XB");
+            locales.remove("en-XA");
+
+            List<Locale> languageMatches = new ArrayList<>();
+            for (String locale : locales) {
+                final Locale l = Locale.forLanguageTag(locale.replace('_', '-'));
+
+                // Only consider locales with both language and country.
+                if (l == null || "und".equals(l.getLanguage())
+                        || l.getLanguage().isEmpty() || l.getCountry().isEmpty()) {
+                    continue;
+                }
+                if (l.getLanguage().equals(target.getLanguage())) {
+                    // If we got a perfect match, we're done.
+                    if (l.getCountry().equals(target.getCountry())) {
+                        Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: got perfect match: "
+                                + l.toLanguageTag());
+                        return l;
+                    }
+
+                    // We've only matched the language, not the country.
+                    languageMatches.add(l);
+                }
+            }
+
+            if (languageMatches.isEmpty()) {
+                Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " + language);
+                return null;
+            }
+
+            Locale bestMatch = lookupFallback(target, languageMatches);
+            if (bestMatch != null) {
+                Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: got a fallback match: "
+                        + bestMatch.toLanguageTag());
+                return bestMatch;
+            } else {
+                // If a locale is "translated", it is selectable in setup wizard, and can therefore
+                // be considered a valid result for this method.
+                if (!TextUtils.isEmpty(target.getCountry())) {
+                    if (isTranslated(context, target)) {
+                        Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: "
+                                + "target locale is translated: " + target);
+                        return target;
+                    }
+                }
+
+                // Somewhat arbitrarily take the first locale for the language,
+                // 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.
+                Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: got language-only match: "
+                        + language);
+                return languageMatches.get(0);
+            }
+        } catch (Exception e) {
+            Rlog.d(LOG_TAG, "getLocaleForLanguageCountry: exception", e);
+        }
+
+        return null;
+    }
+
+    /**
+     * Given a GSM Mobile Country Code, returns
+     * an ISO 2-3 character language code if available.
+     * Returns null if unavailable.
+     */
+    public static String defaultLanguageForMcc(int mcc) {
+        MccTable.MccEntry entry = MccTable.entryForMcc(mcc);
+        if (entry == null) {
+            Rlog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): no country for mcc");
+            return null;
+        }
+
+        final String country = entry.mIso;
+
+        // Choose English as the default language for India.
+        if ("in".equals(country)) {
+            return "en";
+        }
+
+        // Ask CLDR for the language this country uses...
+        ULocale likelyLocale = ULocale.addLikelySubtags(new ULocale("und", country));
+        String likelyLanguage = likelyLocale.getLanguage();
+        Rlog.d(LOG_TAG, "defaultLanguageForMcc(" + mcc + "): country " + country + " uses "
+                + likelyLanguage);
+        return likelyLanguage;
+    }
+
+    private static boolean isTranslated(Context context, Locale targetLocale) {
+        ULocale fullTargetLocale = ULocale.addLikelySubtags(ULocale.forLocale(targetLocale));
+        String language = fullTargetLocale.getLanguage();
+        String script = fullTargetLocale.getScript();
+
+        for (String localeId : context.getAssets().getLocales()) {
+            ULocale fullLocale = ULocale.addLikelySubtags(new ULocale(localeId));
+            if (language.equals(fullLocale.getLanguage())
+                    && script.equals(fullLocale.getScript())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Finds a suitable locale among {@code candidates} to use as the fallback locale for
+     * {@code target}. This looks through the list of {@link MccTable#FALLBACKS},
+     * and follows the chain until a locale in {@code candidates} is found.
+     * This function assumes that {@code target} is not in {@code candidates}.
+     *
+     * TODO: This should really follow the CLDR chain of parent locales! That might be a bit
+     * of a problem because we don't really have an en-001 locale on android.
+     *
+     * @return The fallback locale or {@code null} if there is no suitable fallback defined in the
+     *         lookup.
+     */
+    private static Locale lookupFallback(Locale target, List<Locale> candidates) {
+        Locale fallback = target;
+        while ((fallback = MccTable.FALLBACKS.get(fallback)) != null) {
+            if (candidates.contains(fallback)) {
+                return fallback;
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/src/java/com/android/internal/telephony/util/TelephonyUtils.java b/src/java/com/android/internal/telephony/util/TelephonyUtils.java
deleted file mode 100644
index 1048e5c..0000000
--- a/src/java/com/android/internal/telephony/util/TelephonyUtils.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2019 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.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.SystemProperties;
-import android.content.pm.ComponentInfo;
-import android.content.pm.ResolveInfo;
-
-/**
- * This class provides various util functions
- */
-public final class TelephonyUtils {
-    /** {@hide} */
-    public static String emptyIfNull(@Nullable String str) {
-        return str == null ? "" : str;
-    }
-
-    public static boolean IS_DEBUGGABLE =
-            SystemProperties.getInt("ro.debuggable", 0) == 1;
-
-    public static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) {
-        if (resolveInfo.activityInfo != null) return resolveInfo.activityInfo;
-        if (resolveInfo.serviceInfo != null) return resolveInfo.serviceInfo;
-        if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo;
-        throw new IllegalStateException("Missing ComponentInfo!");
-    }
-  }
diff --git a/telephony-resources/TelephonyResource.java b/telephony-resources/TelephonyResource.java
new file mode 100644
index 0000000..d048bb0
--- /dev/null
+++ b/telephony-resources/TelephonyResource.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 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.telephony.resources;
+
+/**
+ * A dummy class to force pick the R.class to apk
+ */
+final class TelephonyResource {
+    TelephonyResource() {
+    }
+}
diff --git a/tests/telephonytests/Android.bp b/tests/telephonytests/Android.bp
index 772a9c9..4690c89 100644
--- a/tests/telephonytests/Android.bp
+++ b/tests/telephonytests/Android.bp
@@ -8,6 +8,7 @@
         "android.test.mock",
         "android.test.runner",
         "ims-common",
+        "unsupportedappusage",
     ],
 
     static_libs: [
@@ -24,5 +25,10 @@
     ],
 
     platform_apis: true,
-    test_suites: ["device-tests"],
+    jarjar_rules: ":jarjar-rules-shared",
+
+    test_suites: [
+        "mts",
+        "device-tests",
+    ],
 }
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsCallSessionListenerTests.java b/tests/telephonytests/src/android/telephony/ims/ImsCallSessionListenerTests.java
new file mode 100644
index 0000000..99461c1
--- /dev/null
+++ b/tests/telephonytests/src/android/telephony/ims/ImsCallSessionListenerTests.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 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 android.telephony.ims;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.telephony.ims.aidl.IImsCallSessionListener;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsCallSessionListenerTests {
+
+    @Mock
+    IImsCallSessionListener mMockListener;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testListenerMayHandoverDeprecated() throws Exception {
+        ImsCallSessionListener mTestListener = new ImsCallSessionListener(mMockListener);
+        mTestListener.callSessionMayHandover(ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN);
+        // verify we get the correct network type equivalent of this param.
+        verify(mMockListener).callSessionMayHandover(TelephonyManager.NETWORK_TYPE_LTE,
+                TelephonyManager.NETWORK_TYPE_IWLAN);
+    }
+
+    @Test
+    public void testListenerHandoverDeprecated() throws Exception {
+        ImsReasonInfo imsReasonInfo = new ImsReasonInfo();
+        ImsCallSessionListener mTestListener = new ImsCallSessionListener(mMockListener);
+        mTestListener.callSessionHandover(ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, imsReasonInfo);
+        // verify we get the correct network type equivalent of this param.
+        verify(mMockListener).callSessionHandover(eq(TelephonyManager.NETWORK_TYPE_LTE),
+                eq(TelephonyManager.NETWORK_TYPE_IWLAN), eq(imsReasonInfo));
+    }
+
+    @Test
+    public void testListenerHandoverFailedDeprecated() throws Exception {
+        ImsReasonInfo imsReasonInfo = new ImsReasonInfo(
+                ImsReasonInfo.CODE_REJECT_ONGOING_HANDOVER, 0 /*extraCode*/);
+        ImsCallSessionListener mTestListener = new ImsCallSessionListener(mMockListener);
+        mTestListener.callSessionHandoverFailed(ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, imsReasonInfo);
+        // verify we get the correct network type equivalent of this param.
+        verify(mMockListener).callSessionHandoverFailed(eq(TelephonyManager.NETWORK_TYPE_LTE),
+                eq(TelephonyManager.NETWORK_TYPE_IWLAN), eq(imsReasonInfo));
+    }
+
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
index 59c36bb..9061ad1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
@@ -88,7 +88,9 @@
     public void testDisableCarrierAppsUntilPrivileged_MissingApp() throws Exception {
         Mockito.when(mPackageManager.getApplicationInfo("com.example.missing.app",
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(null);
         ArraySet<String> systemCarrierAppsDisabledUntilUsed = new ArraySet<>();
         systemCarrierAppsDisabledUntilUsed.add("com.example.missing.app");
@@ -111,7 +113,8 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
                 mTelephonyManager, mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
@@ -135,10 +138,15 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
+
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
@@ -158,10 +166,15 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
@@ -181,10 +194,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
@@ -205,11 +222,16 @@
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
                 | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
@@ -232,11 +254,15 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
                 .thenReturn(appInfo);
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
@@ -264,18 +290,23 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
                 .thenReturn(appInfo);
         ApplicationInfo associatedAppInfo = new ApplicationInfo();
         associatedAppInfo.packageName = ASSOCIATED_APP;
         associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-        associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
@@ -303,21 +334,26 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(CARRIER_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         ApplicationInfo associatedAppInfo = new ApplicationInfo();
         associatedAppInfo.packageName = ASSOCIATED_APP;
         associatedAppInfo.flags |=
                 ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-        associatedAppInfo.enabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(ASSOCIATED_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
         Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
-                .thenReturn(associatedAppInfo);
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
+                .thenReturn(null);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
@@ -344,19 +380,24 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(CARRIER_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         ApplicationInfo associatedAppInfo = new ApplicationInfo();
         associatedAppInfo.packageName = ASSOCIATED_APP;
         associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-        associatedAppInfo.enabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(ASSOCIATED_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
         Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
@@ -380,10 +421,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -405,10 +450,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
@@ -428,10 +477,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -452,10 +505,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
@@ -475,10 +532,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -499,10 +560,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
@@ -523,10 +588,14 @@
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
                 | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -548,14 +617,18 @@
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= (ApplicationInfo.FLAG_SYSTEM
                 | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP | ApplicationInfo.FLAG_INSTALLED);
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
-                ASSOCIATED_APPS);
+                null /* telephonyManager */, mContentResolver,
+                USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager).setSystemAppHiddenUntilInstalled(
                 CARRIER_APP, true);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppInstallState(
@@ -575,18 +648,24 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(CARRIER_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         ApplicationInfo associatedAppInfo = new ApplicationInfo();
         associatedAppInfo.packageName = ASSOCIATED_APP;
         associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-        associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(ASSOCIATED_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -615,18 +694,24 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(CARRIER_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         ApplicationInfo associatedAppInfo = new ApplicationInfo();
         associatedAppInfo.packageName = ASSOCIATED_APP;
         associatedAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager.getApplicationEnabledSetting(ASSOCIATED_APP, USER_ID))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -657,10 +742,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         ApplicationInfo associatedAppInfo = new ApplicationInfo();
         associatedAppInfo.packageName = ASSOCIATED_APP;
@@ -668,7 +757,9 @@
         associatedAppInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(ASSOCIATED_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, USER_ID))
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY, USER_ID))
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -693,14 +784,18 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
-                ASSOCIATED_APPS);
+                null /* telephonyManager */, mContentResolver,
+                USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager).setSystemAppHiddenUntilInstalled(
                 CARRIER_APP, true);
         Mockito.verify(mPackageManager).setSystemAppInstallState(
@@ -719,10 +814,14 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
@@ -746,14 +845,18 @@
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
-        appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString(), Mockito.anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY
+                        | PackageManager.MATCH_FACTORY_ONLY,
                 USER_ID)).thenReturn(appInfo);
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
-                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
-                ASSOCIATED_APPS);
+                null /* telephonyManager */, mContentResolver,
+                USER_ID, CARRIER_APPS, ASSOCIATED_APPS);
         Mockito.verify(mPackageManager).setSystemAppHiddenUntilInstalled(
                 CARRIER_APP, true);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppInstallState(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java
index 1fad90f..10b31a5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 
+import android.os.Message;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -81,4 +82,15 @@
         assertNotNull(mCarrierServiceBindHelper.mBindings.get(0));
         assertNotNull(mCarrierServiceBindHelper.mLastSimState.get(0));
     }
+
+    @Test
+    public void testUnbindWhenNotBound() throws Exception {
+        mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
+
+        // Try unbinding without binding and make sure we don't throw an Exception
+        mCarrierServiceBindHelper.mHandler.handleMessage(
+                Message.obtain(mCarrierServiceBindHelper.mHandler,
+                        CarrierServiceBindHelper.EVENT_PERFORM_IMMEDIATE_UNBIND,
+                        new Integer(0)));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
index bf36e73..27ffeef 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
@@ -145,8 +145,8 @@
         notificationTypeMap.put(CarrierServiceStateTracker.NOTIFICATION_PREF_NETWORK,
                 spyPrefNetworkNotification);
         Notification.Builder mNotificationBuilder = new Notification.Builder(mContext);
-        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getVoiceRegState();
-        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getDataRegState();
+        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getState();
+        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getDataRegistrationState();
         doReturn(true).when(mSST).isRadioOn();
         doReturn(mNotificationBuilder).when(spyPrefNetworkNotification).getNotificationBuilder();
 
@@ -187,7 +187,6 @@
         notificationTypeMap.put(CarrierServiceStateTracker.NOTIFICATION_EMERGENCY_NETWORK,
                 spyEmergencyNetworkNotification);
         Notification.Builder mNotificationBuilder = new Notification.Builder(mContext);
-        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getVoiceRegState();
         doReturn(mNotificationBuilder).when(spyEmergencyNetworkNotification)
                 .getNotificationBuilder();
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java
index 6fd43e6..a10dc9b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java
@@ -39,8 +39,8 @@
 import android.service.carrier.ICarrierMessagingService;
 import android.service.carrier.MessagePdu;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.LocalLog;
 
+import com.android.internal.telephony.LocalLog;
 import com.android.internal.telephony.uicc.UiccCard;
 
 import org.junit.After;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java
index 8246094..9030124 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java
@@ -15,9 +15,8 @@
  */
 package com.android.internal.telephony;
 
-import static com.android.internal.telephony.TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE;
-import static com.android.internal.telephony.TelephonyIntents
-        .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED;
+import static android.telephony.TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE;
+import static android.telephony.TelephonyManager.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyLong;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CbGeoUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/CbGeoUtilsTest.java
index 787cb43..f9b3599 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CbGeoUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CbGeoUtilsTest.java
@@ -18,10 +18,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.android.internal.telephony.CbGeoUtils.Circle;
-import com.android.internal.telephony.CbGeoUtils.Geometry;
-import com.android.internal.telephony.CbGeoUtils.LatLng;
-import com.android.internal.telephony.CbGeoUtils.Polygon;
+import android.telephony.CbGeoUtils;
+import android.telephony.CbGeoUtils.Circle;
+import android.telephony.CbGeoUtils.Geometry;
+import android.telephony.CbGeoUtils.LatLng;
+import android.telephony.CbGeoUtils.Polygon;
 
 import org.junit.Test;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java
index f50cea1..1a77ea4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java
@@ -21,8 +21,9 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-/** Unit tests for {@link CellIdentityGsm}. */
+import java.util.Collections;
 
+/** Unit tests for {@link CellIdentityGsm}. */
 public class CellIdentityGsmTest extends AndroidTestCase {
 
     // Location Area Code ranges from 0 to 65535.
@@ -45,7 +46,7 @@
     public void testDefaultConstructor() {
         CellIdentityGsm ci =
                 new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList());
 
         assertEquals(LAC, ci.getLac());
         assertEquals(CID, ci.getCid());
@@ -66,7 +67,7 @@
         final String mncWithThreeDigit = "061";
         CellIdentityGsm ci =
                 new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, mncWithThreeDigit,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList());
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(61, ci.getMnc());
@@ -80,7 +81,7 @@
         final String mncWithTwoDigit = "61";
         CellIdentityGsm ci =
                 new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, mncWithTwoDigit,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList());
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(61, ci.getMnc());
@@ -92,7 +93,8 @@
     @SmallTest
     public void testConstructorWithEmptyMccMnc() {
         CellIdentityGsm ci =
-                new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT);
+                new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList());
 
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -100,7 +102,8 @@
         assertNull(ci.getMncString());
         assertNull(ci.getMobileNetworkOperator());
 
-        ci = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT);
+        ci = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -108,7 +111,8 @@
         assertNull(ci.getMncString());
         assertNull(ci.getMobileNetworkOperator());
 
-        ci = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+        ci = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
 
         assertEquals(MNC, ci.getMnc());
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
@@ -116,7 +120,8 @@
         assertNull(ci.getMccString());
         assertNull(ci.getMobileNetworkOperator());
 
-        ci = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, "", "", ALPHA_LONG, ALPHA_SHORT);
+        ci = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, "", "", ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
 
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -128,20 +133,26 @@
     @SmallTest
     public void testEquals() {
         CellIdentityGsm ciA = new CellIdentityGsm(
-                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
         CellIdentityGsm ciB = new CellIdentityGsm(
-                LAC, CID, ARFCN, BSIC,  MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, ARFCN, BSIC,  MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
 
         assertTrue(ciA.equals(ciB));
 
-        ciA = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
-        ciB = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+        ciA = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
+        ciB = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
 
         assertTrue(ciA.equals(ciB));
 
         ciA = new CellIdentityGsm(
-                LAC, CID, ARFCN, BSIC, MCC_STR,  MNC_STR, ALPHA_LONG, ALPHA_SHORT);
-        ciB = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, ARFCN, BSIC, MCC_STR,  MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
+        ciB = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
 
         assertFalse(ciA.equals(ciB));
     }
@@ -150,7 +161,7 @@
     public void testParcel() {
         CellIdentityGsm ci =
                 new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList());
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
@@ -163,7 +174,8 @@
     @SmallTest
     public void testParcelWithUnknowMccMnc() {
         CellIdentityGsm ci =
-                new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT);
+                new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList());
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
@@ -178,7 +190,8 @@
         final String invalidMcc = "randomStuff";
         final String invalidMnc = "randomStuff";
         CellIdentityGsm ci =
-                new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT);
+                new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList());
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java
index bb0b6fa..8664fd5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java
@@ -22,6 +22,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import java.util.Collections;
+
 /** Unit tests for {@link CellIdentityLte}. */
 
 public class CellIdentityLteTest extends AndroidTestCase {
@@ -46,7 +48,7 @@
     public void testDefaultConstructor() {
         CellIdentityLte ci =
                 new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         assertEquals(CI, ci.getCi());
         assertEquals(PCI, ci.getPci());
@@ -68,7 +70,7 @@
         final String mncWithThreeDigit = "061";
         CellIdentityLte ci =
                 new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, mncWithThreeDigit,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(61, ci.getMnc());
@@ -82,7 +84,7 @@
         final String mncWithTwoDigit = "61";
         CellIdentityLte ci =
                 new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, mncWithTwoDigit,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(61, ci.getMnc());
@@ -94,7 +96,8 @@
     @SmallTest
     public void testConstructorWithEmptyMccMnc() {
         CellIdentityLte ci = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -103,7 +106,8 @@
         assertNull(ci.getMobileNetworkOperator());
 
         ci = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -112,7 +116,8 @@
         assertNull(ci.getMobileNetworkOperator());
 
         ci = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertEquals(MNC, ci.getMnc());
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
@@ -121,7 +126,8 @@
         assertNull(ci.getMobileNetworkOperator());
 
         ci = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, "", "", ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, "", "", ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -152,23 +158,29 @@
     @SmallTest
     public void testEquals() {
         CellIdentityLte ciA = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellIdentityLte ciB = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertTrue(ciA.equals(ciB));
 
         ciA = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         ciB = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertTrue(ciA.equals(ciB));
 
         ciA = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         ciB = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertFalse(ciA.equals(ciB));
     }
@@ -177,7 +189,7 @@
     public void testParcel() {
         CellIdentityLte ci =
                 new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
@@ -190,7 +202,8 @@
     @SmallTest
     public void testParcelWithUnknownMccMnc() {
         CellIdentityLte ci = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         p.writeInt(CellInfo.TYPE_LTE);
@@ -214,7 +227,8 @@
         final String invalidMcc = "randomStuff";
         final String invalidMnc = "randomStuff";
         CellIdentityLte ci = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         p.writeInt(CellInfo.TYPE_LTE);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java
index ed7fc1c..28dc81b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java
@@ -19,12 +19,18 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.Parcel;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.CellIdentityNr;
 import android.telephony.CellInfo;
 import android.test.AndroidTestCase;
 
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
 public class CellIdentityNrTest extends AndroidTestCase {
     private static final String MCC = "310";
     private static final String MNC = "260";
@@ -36,12 +42,15 @@
     private static final int PCI = 123;
     private static final int TAC = 32767;
     private static final int NCI = 8675309;
+    private static final List<Integer> BANDS = new ArrayList<>(Arrays.asList(
+            AccessNetworkConstants.NgranBands.BAND_1, AccessNetworkConstants.NgranBands.BAND_1));
 
     @Test
     public void testGetMethod() {
         // GIVEN an instance of CellIdentityNr
         CellIdentityNr cellIdentityNr =
-                new CellIdentityNr(PCI, TAC, NRARFCN, MCC, MNC, NCI, ALPHAL, ALPHAS);
+                new CellIdentityNr(PCI, TAC, NRARFCN, BANDS, MCC, MNC, NCI, ALPHAL, ALPHAS,
+                        Collections.emptyList());
 
         // THEN the get method should return correct value
         assertThat(cellIdentityNr.getType()).isEqualTo(CellInfo.TYPE_NR);
@@ -60,9 +69,11 @@
     public void testEquals_sameParameters() {
         // GIVEN an instance of CellIdentityNr, and create another object with the same parameters
         CellIdentityNr cellIdentityNr =
-                new CellIdentityNr(PCI, TAC, NRARFCN, MCC, MNC, NCI, ALPHAL, ALPHAS);
+                new CellIdentityNr(PCI, TAC, NRARFCN, BANDS, MCC, MNC, NCI,
+                        ALPHAL, ALPHAS, Collections.emptyList());
         CellIdentityNr anotherCellIdentityNr =
-                new CellIdentityNr(PCI, TAC, NRARFCN, MCC, MNC, NCI, ALPHAL, ALPHAS);
+                new CellIdentityNr(PCI, TAC, NRARFCN, BANDS, MCC, MNC, NCI,
+                        ALPHAL, ALPHAS, Collections.emptyList());
 
         // THEN this two objects are equivalent
         assertThat(cellIdentityNr).isEqualTo(anotherCellIdentityNr);
@@ -72,9 +83,11 @@
     public void testEquals_differentParameters() {
         // GIVEN an instance of CellIdentityNr, and create another object with different parameters
         CellIdentityNr cellIdentityNr =
-                new CellIdentityNr(PCI, TAC, NRARFCN, MCC, MNC, NCI, ALPHAL, ALPHAS);
+                new CellIdentityNr(PCI, TAC, NRARFCN, BANDS, MCC, MNC, NCI,
+                        ALPHAL, ALPHAS, Collections.emptyList());
         CellIdentityNr anotherCellIdentityNr =
-                new CellIdentityNr(PCI, TAC, NRARFCN, MCC, MNC, NCI + 1, ALPHAL, ALPHAS);
+                new CellIdentityNr(PCI, TAC, NRARFCN, BANDS, MCC, MNC, NCI + 1,
+                        ALPHAL, ALPHAS, Collections.emptyList());
 
         // THEN this two objects are different
         assertThat(cellIdentityNr).isNotEqualTo(anotherCellIdentityNr);
@@ -84,7 +97,8 @@
     public void testParcel() {
         // GIVEN an instance of CellIdentityNr
         CellIdentityNr cellIdentityNr =
-                new CellIdentityNr(PCI, TAC, NRARFCN, MCC, MNC, NCI, ALPHAL, ALPHAS);
+                new CellIdentityNr(PCI, TAC, NRARFCN, BANDS, MCC, MNC, NCI,
+                        ALPHAL, ALPHAS, Collections.emptyList());
 
         // WHEN write the object to parcel and create another object with that parcel
         Parcel parcel = Parcel.obtain();
@@ -93,11 +107,12 @@
         CellIdentityNr anotherCellIdentityNr = CellIdentityNr.CREATOR.createFromParcel(parcel);
 
         // THEN the new object is equal to the old one
-        assertThat(anotherCellIdentityNr).isEqualTo(anotherCellIdentityNr);
+        assertThat(anotherCellIdentityNr).isEqualTo(cellIdentityNr);
         assertThat(anotherCellIdentityNr.getType()).isEqualTo(CellInfo.TYPE_NR);
         assertThat(anotherCellIdentityNr.getNrarfcn()).isEqualTo(NRARFCN);
         assertThat(anotherCellIdentityNr.getPci()).isEqualTo(PCI);
         assertThat(anotherCellIdentityNr.getTac()).isEqualTo(TAC);
+        assertThat(anotherCellIdentityNr.getBands()).isEqualTo(BANDS);
         assertThat(anotherCellIdentityNr.getOperatorAlphaLong()).isEqualTo(ALPHAL);
         assertThat(anotherCellIdentityNr.getOperatorAlphaShort()).isEqualTo(ALPHAS);
         assertThat(anotherCellIdentityNr.getMccString()).isEqualTo(MCC);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTdscdmaTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTdscdmaTest.java
index 78c5547..a0c67a5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTdscdmaTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTdscdmaTest.java
@@ -24,6 +24,8 @@
 
 /** Unit tests for {@link CellIdentityTdscdma}. */
 
+import java.util.Collections;
+
 public class CellIdentityTdscdmaTest extends AndroidTestCase {
 
     // Cell identity ranges from 0 to 268435456.
@@ -67,7 +69,8 @@
     public void testConstructor() {
         CellIdentityTdscdma ci =
                 new CellIdentityTdscdma(
-                        MCC_STR, MNC_STR, LAC, CID, CPID, UARFCN, ALPHA_LONG, ALPHA_SHORT);
+                        MCC_STR, MNC_STR, LAC, CID, CPID, UARFCN, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList(), null);
 
         assertEquals(MCC_STR, ci.getMccString());
         assertEquals(MNC_STR, ci.getMncString());
@@ -83,22 +86,25 @@
     @SmallTest
     public void testConstructorWithEmptyMccMnc() {
         CellIdentityTdscdma ci = new CellIdentityTdscdma(
-                null, null, LAC, CID, CPID, UARFCN, "", "");
+                null, null, LAC, CID, CPID, UARFCN, "", "", Collections.emptyList(), null);
 
         assertNull(ci.getMccString());
         assertNull(ci.getMncString());
 
-        ci = new CellIdentityTdscdma(MCC_STR, null, LAC, CID, CPID, UARFCN, "", "");
+        ci = new CellIdentityTdscdma(MCC_STR, null, LAC, CID, CPID, UARFCN, "", "",
+                Collections.emptyList(), null);
 
         assertEquals(MCC_STR, ci.getMccString());
         assertNull(ci.getMncString());
 
-        ci = new CellIdentityTdscdma(null, MNC_STR, LAC, CID, CPID, UARFCN, "", "");
+        ci = new CellIdentityTdscdma(null, MNC_STR, LAC, CID, CPID, UARFCN, "", "",
+                Collections.emptyList(), null);
 
         assertEquals(MNC_STR, ci.getMncString());
         assertNull(ci.getMccString());
 
-        ci = new CellIdentityTdscdma("", "", LAC, CID, CPID, UARFCN, "", "");
+        ci = new CellIdentityTdscdma("", "", LAC, CID, CPID, UARFCN, "", "",
+                Collections.emptyList(), null);
 
         assertNull(ci.getMccString());
         assertNull(ci.getMncString());
@@ -107,7 +113,8 @@
     @SmallTest
     public void testParcel() {
         CellIdentityTdscdma ci = new CellIdentityTdscdma(
-                MCC_STR, MNC_STR, LAC, CID, UARFCN, CPID, ALPHA_LONG, ALPHA_SHORT);
+                MCC_STR, MNC_STR, LAC, CID, UARFCN, CPID, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
@@ -121,7 +128,8 @@
     public void testParcelWithUnknowMccMnc() {
         CellIdentityTdscdma ci =
                 new CellIdentityTdscdma(
-                        null, null, LAC, CID, CPID, UARFCN, ALPHA_LONG, ALPHA_SHORT);
+                        null, null, LAC, CID, CPID, UARFCN, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         p.writeInt(CellInfo.TYPE_TDSCDMA);
@@ -145,7 +153,8 @@
         final String invalidMnc = "randomStuff";
         CellIdentityTdscdma ci =
                 new CellIdentityTdscdma(
-                        null, null, LAC, CID, CPID, UARFCN, ALPHA_LONG, ALPHA_SHORT);
+                        null, null, LAC, CID, CPID, UARFCN, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         p.writeInt(CellInfo.TYPE_TDSCDMA);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTest.java
index 6b65a46..166c89c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityTest.java
@@ -25,6 +25,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import java.util.Collections;
+
 public class CellIdentityTest extends AndroidTestCase {
 
     // Cell identity ranges from 0 to 268435456.
@@ -67,14 +69,16 @@
     @SmallTest
     public void testConstructCellIdentityGsm() {
         // Test values below zero (these must all be non-negative)
-        CellIdentityGsm gsm = new CellIdentityGsm(-1, -1, -1, -1, null, null, null, null);
+        CellIdentityGsm gsm = new CellIdentityGsm(-1, -1, -1, -1, null, null, null, null,
+                Collections.emptyList());
         assertEquals(CellInfo.UNAVAILABLE, gsm.getLac());
         assertEquals(CellInfo.UNAVAILABLE, gsm.getCid());
         assertEquals(CellInfo.UNAVAILABLE, gsm.getArfcn());
         assertEquals(CellInfo.UNAVAILABLE, gsm.getBsic());
 
         // Test max values of LAC, CID, ARFCN, and BSIC
-        gsm = new CellIdentityGsm(MAX_LAC, MAX_CID, MAX_ARFCN, MAX_BSIC, null, null, null, null);
+        gsm = new CellIdentityGsm(MAX_LAC, MAX_CID, MAX_ARFCN, MAX_BSIC, null, null, null, null,
+                Collections.emptyList());
         assertEquals(MAX_LAC, gsm.getLac());
         assertEquals(MAX_CID, gsm.getCid());
         assertEquals(MAX_ARFCN, gsm.getArfcn());
@@ -82,7 +86,8 @@
 
         // Test max values + 1 of LAC, CID, ARFCN, and BSIC
         gsm = new CellIdentityGsm(
-                MAX_LAC + 1, MAX_CID + 1, MAX_ARFCN + 1, MAX_BSIC + 1, null, null, null, null);
+                MAX_LAC + 1, MAX_CID + 1, MAX_ARFCN + 1, MAX_BSIC + 1, null, null, null, null,
+                Collections.emptyList());
         assertEquals(CellInfo.UNAVAILABLE, gsm.getLac());
         assertEquals(CellInfo.UNAVAILABLE, gsm.getCid());
         assertEquals(CellInfo.UNAVAILABLE, gsm.getArfcn());
@@ -93,23 +98,25 @@
     @SmallTest
     public void testEquals() {
         CellIdentity ciA = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellIdentity ciB = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertTrue(ciA.equals(ciB));
 
         ciA = new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG,
-                ALPHA_SHORT);
+                ALPHA_SHORT, Collections.emptyList(), null);
         ciB = new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG,
-                ALPHA_SHORT);
+                ALPHA_SHORT, Collections.emptyList(), null);
 
         assertTrue(ciA.equals(ciB));
 
         ciA = new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, null, ALPHA_LONG,
-                ALPHA_SHORT);
+                ALPHA_SHORT, Collections.emptyList(), null);
         ciB = new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG,
-                ALPHA_SHORT);
+                ALPHA_SHORT, Collections.emptyList(), null);
 
         assertFalse(ciA.equals(ciB));
     }
@@ -117,7 +124,7 @@
     @SmallTest
     public void testParcel() {
         CellIdentity ci = new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR,
-                ALPHA_LONG, ALPHA_SHORT);
+                ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java
index c978c28..86a256b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java
@@ -21,6 +21,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import java.util.Collections;
+
 /** Unit tests for {@link CellIdentityWcdma}. */
 
 public class CellIdentityWcdmaTest extends AndroidTestCase {
@@ -44,7 +46,7 @@
     public void testDefaultConstructor() {
         CellIdentityWcdma ci =
                 new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         assertEquals(LAC, ci.getLac());
         assertEquals(CID, ci.getCid());
@@ -65,7 +67,7 @@
         final String mncWithThreeDigit = "061";
         CellIdentityWcdma ci =
                 new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, mncWithThreeDigit,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(61, ci.getMnc());
@@ -79,7 +81,7 @@
         final String mncWithTwoDigit = "61";
         CellIdentityWcdma ci =
                 new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, mncWithTwoDigit,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(61, ci.getMnc());
@@ -92,7 +94,8 @@
     public void testConstructorWithEmptyMccMnc() {
         final String integerMaxValue = String.valueOf(Integer.MAX_VALUE);
         CellIdentityWcdma ci =
-                new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
+                new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList(), null);
 
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -100,7 +103,8 @@
         assertNull(ci.getMncString());
         assertNull(ci.getMobileNetworkOperator());
 
-        ci = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT);
+        ci = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertEquals(MCC, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -108,7 +112,8 @@
         assertNull(ci.getMncString());
         assertNull(ci.getMobileNetworkOperator());
 
-        ci = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+        ci = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertEquals(MNC, ci.getMnc());
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
@@ -116,7 +121,8 @@
         assertNull(ci.getMccString());
         assertNull(ci.getMobileNetworkOperator());
 
-        ci = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, "", "", ALPHA_LONG, ALPHA_SHORT);
+        ci = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, "", "", ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertEquals(Integer.MAX_VALUE, ci.getMcc());
         assertEquals(Integer.MAX_VALUE, ci.getMnc());
@@ -128,19 +134,25 @@
     @SmallTest
     public void testEquals() {
         CellIdentityWcdma ciA = new CellIdentityWcdma(
-                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellIdentityWcdma ciB = new CellIdentityWcdma(
-                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertTrue(ciA.equals(ciB));
 
-        ciA = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
-        ciB = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
+        ciA = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
+        ciB = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertTrue(ciA.equals(ciB));
 
-        ciA = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT);
-        ciB = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
+        ciA = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
+        ciB = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
 
         assertFalse(ciA.equals(ciB));
     }
@@ -149,7 +161,7 @@
     public void testParcel() {
         CellIdentityWcdma ci =
                 new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR,
-                        ALPHA_LONG, ALPHA_SHORT);
+                        ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
@@ -162,7 +174,8 @@
     @SmallTest
     public void testParcelWithUnknowMccMnc() {
         CellIdentityWcdma ci =
-                new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
+                new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
@@ -177,7 +190,8 @@
         final String invalidMcc = "randomStuff";
         final String invalidMnc = "randomStuff";
         CellIdentityWcdma ci =
-                new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
+                new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT,
+                        Collections.emptyList(), null);
 
         Parcel p = Parcel.obtain();
         ci.writeToParcel(p, 0);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
index d967bf6..a2e765e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
@@ -18,7 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.hardware.radio.V1_4.NrSignalStrength;
 import android.os.Parcel;
+import android.telephony.CellInfo;
 import android.telephony.CellSignalStrength;
 import android.telephony.CellSignalStrengthNr;
 import android.test.AndroidTestCase;
@@ -57,6 +59,50 @@
     }
 
     @Test
+    public void testGetMethodWithHal() {
+        // GIVEN an instance of NrSignalStrength with some positive values
+        NrSignalStrength nrSignalStrength = new NrSignalStrength();
+        nrSignalStrength.csiRsrp = -CSIRSRP;
+        nrSignalStrength.csiRsrq = -CSIRSRQ;
+        nrSignalStrength.csiSinr = CSISINR;
+        nrSignalStrength.ssRsrp = -SSRSRP;
+        nrSignalStrength.ssRsrq = -SSRSRQ;
+        nrSignalStrength.ssSinr = SSSINR;
+
+        // THEN the get method should return the correct value
+        CellSignalStrengthNr css = new CellSignalStrengthNr(nrSignalStrength);
+        assertThat(css.getCsiRsrp()).isEqualTo(CSIRSRP);
+        assertThat(css.getCsiRsrq()).isEqualTo(CSIRSRQ);
+        assertThat(css.getCsiSinr()).isEqualTo(CSISINR);
+        assertThat(css.getSsRsrp()).isEqualTo(SSRSRP);
+        assertThat(css.getSsRsrq()).isEqualTo(SSRSRQ);
+        assertThat(css.getSsSinr()).isEqualTo(SSSINR);
+        assertThat(css.getDbm()).isEqualTo(SSRSRP);
+    }
+
+    @Test
+    public void testUnavailableValueWithHal() {
+        // GIVEN an instance of NrSignalStrength
+        NrSignalStrength nrSignalStrength = new NrSignalStrength();
+        nrSignalStrength.csiRsrp = CellInfo.UNAVAILABLE;
+        nrSignalStrength.csiRsrq = CellInfo.UNAVAILABLE;
+        nrSignalStrength.csiSinr = CellInfo.UNAVAILABLE;
+        nrSignalStrength.ssRsrp = CellInfo.UNAVAILABLE;
+        nrSignalStrength.ssRsrq = CellInfo.UNAVAILABLE;
+        nrSignalStrength.ssSinr = CellInfo.UNAVAILABLE;
+
+        // THEN the get method should return unavailable value
+        CellSignalStrengthNr css = new CellSignalStrengthNr(nrSignalStrength);
+        assertThat(css.getCsiRsrp()).isEqualTo(CellInfo.UNAVAILABLE);
+        assertThat(css.getCsiRsrq()).isEqualTo(CellInfo.UNAVAILABLE);
+        assertThat(css.getCsiSinr()).isEqualTo(CellInfo.UNAVAILABLE);
+        assertThat(css.getSsRsrp()).isEqualTo(CellInfo.UNAVAILABLE);
+        assertThat(css.getSsRsrq()).isEqualTo(CellInfo.UNAVAILABLE);
+        assertThat(css.getSsSinr()).isEqualTo(CellInfo.UNAVAILABLE);
+        assertThat(css.getDbm()).isEqualTo(CellInfo.UNAVAILABLE);
+    }
+
+    @Test
     public void testEquals_sameParameters() {
         // GIVEN an instance of CellSignalStrengthNr and another object with the same parameters
         CellSignalStrengthNr css = new CellSignalStrengthNr(
@@ -109,11 +155,9 @@
                     CSIRSRP, CSIRSRQ, CSISINR, ssRsrp, SSRSRQ, SSSINR);
 
             // THEN the signal level is valid
-            assertThat(css.getLevel()).isAnyOf(
-                    CellSignalStrength.SIGNAL_STRENGTH_GREAT,
-                    CellSignalStrength.SIGNAL_STRENGTH_GOOD,
-                    CellSignalStrength.SIGNAL_STRENGTH_MODERATE,
-                    CellSignalStrength.SIGNAL_STRENGTH_POOR);
+            assertThat(css.getLevel()).isIn(Range.range(
+                    CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, BoundType.CLOSED,
+                    CellSignalStrength.SIGNAL_STRENGTH_GREAT, BoundType.CLOSED));
         }
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
index 470482b..e564da5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
@@ -27,6 +27,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
 import android.telephony.PhoneCapability;
 import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -45,9 +46,9 @@
     private CellularNetworkValidator mValidatorUT;
     private int mValidatedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private static final PhoneCapability CAPABILITY_WITH_VALIDATION_SUPPORTED =
-            new PhoneCapability(1, 1, 0, null, true);
+            new PhoneCapability(0, 0, 0, 0, 1, 0, null, null, null, null, null, null, null);
     private static final PhoneCapability CAPABILITY_WITHOUT_VALIDATION_SUPPORTED =
-            new PhoneCapability(1, 1, 0, null, false);
+            new PhoneCapability(0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null);
 
     CellularNetworkValidator.ValidationCallback mCallback = (validated, subId) -> {
         mValidated = validated;
@@ -74,7 +75,7 @@
      */
     @Test
     @SmallTest
-    public void testValidationSupported() throws Exception {
+    public void testValidationSupported() {
         doReturn(CAPABILITY_WITH_VALIDATION_SUPPORTED).when(mPhoneConfigurationManager)
                 .getCurrentPhoneCapability();
         assertTrue(mValidatorUT.isValidationFeatureSupported());
@@ -89,13 +90,14 @@
      */
     @Test
     @SmallTest
-    public void testValidateSuccess() throws Exception {
+    public void testValidateSuccess() {
         int subId = 1;
         int timeout = 1000;
         NetworkRequest expectedRequest = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                .setNetworkSpecifier(String.valueOf(subId))
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                        .setSubscriptionId(subId).build())
                 .build();
 
         mValidatorUT.validate(subId, timeout, true, mCallback);
@@ -122,13 +124,14 @@
      */
     @Test
     @SmallTest
-    public void testValidateTimeout() throws Exception {
+    public void testValidateTimeout() {
         int subId = 1;
         int timeout = 100;
         NetworkRequest expectedRequest = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                .setNetworkSpecifier(String.valueOf(subId))
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                        .setSubscriptionId(subId).build())
                 .build();
 
         mValidatorUT.validate(subId, timeout, true, mCallback);
@@ -156,13 +159,14 @@
      */
     @Test
     @SmallTest
-    public void testValidateFailure() throws Exception {
+    public void testValidateFailure() {
         int subId = 1;
         int timeout = 100;
         NetworkRequest expectedRequest = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                .setNetworkSpecifier(String.valueOf(subId))
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                        .setSubscriptionId(subId).build())
                 .build();
 
         mValidatorUT.validate(subId, timeout, true, mCallback);
@@ -188,13 +192,14 @@
      */
     @Test
     @SmallTest
-    public void testNetworkAvailableNotValidated() throws Exception {
+    public void testNetworkAvailableNotValidated() {
         int subId = 1;
         int timeout = 100;
         NetworkRequest expectedRequest = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                .setNetworkSpecifier(String.valueOf(subId))
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                        .setSubscriptionId(subId).build())
                 .build();
 
         mValidatorUT.validate(subId, timeout, true, mCallback);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java b/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java
index f7132b8..d406996 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java
@@ -16,12 +16,7 @@
 
 package com.android.internal.telephony;
 
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-
-import android.os.Build;
-import android.util.Log;
-import android.telephony.Rlog;
-import android.telephony.TelephonyHistogram;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import junit.framework.Assert;
 import junit.framework.TestCase;
@@ -87,7 +82,7 @@
     }
 
     public void testStartAttributingWithZeroConcurrentRequests() throws Exception {
-        if(Build.IS_DEBUGGABLE) {
+        if (TelephonyUtils.IS_DEBUGGABLE) {
             try {
                 mClient.startAttributingWakelock(15, 25, 0, 100);
                 fail("Expecting an illegal argument Exception to be thrown");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index fc4dcc6..a708219 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doAnswer;
@@ -52,6 +54,7 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.net.ConnectivityManager;
+import android.net.Network;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
@@ -61,7 +64,6 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.telephony.TelephonyRegistryManager;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Telephony.ServiceStateTable;
@@ -69,6 +71,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
 import android.telephony.euicc.EuiccManager;
 import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
@@ -315,18 +318,16 @@
 
         @Override
         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
-            return registerReceiver(receiver, filter, null, null);
+            return registerReceiverFakeImpl(receiver, filter);
         }
 
         @Override
         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                 String broadcastPermission, Handler scheduler) {
-            return registerReceiverAsUser(receiver, null, filter, broadcastPermission, scheduler);
+            return registerReceiverFakeImpl(receiver, filter);
         }
 
-        @Override
-        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
-                IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        private Intent registerReceiverFakeImpl(BroadcastReceiver receiver, IntentFilter filter) {
             Intent result = null;
             synchronized (mBroadcastReceiversByAction) {
                 for (int i = 0 ; i < filter.countActions() ; i++) {
@@ -410,6 +411,11 @@
         }
 
         @Override
+        public Context createContextAsUser(UserHandle user, int flags) {
+            return this;
+        }
+
+        @Override
         public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
                 String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
                 int initialCode, String initialData, Bundle initialExtras) {
@@ -451,6 +457,20 @@
         }
 
         @Override
+        public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+                String receiverAppOp, Bundle options, BroadcastReceiver resultReceiver,
+                Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+            logd("sendOrderedBroadcast called for " + intent.getAction());
+            mLastBroadcastOptions = options;
+            sendBroadcast(intent);
+            if (resultReceiver != null) {
+                synchronized (mOrderedBroadcastReceivers) {
+                    mOrderedBroadcastReceivers.put(intent, resultReceiver);
+                }
+            }
+        }
+
+        @Override
         public void sendStickyBroadcast(Intent intent) {
             logd("sendStickyBroadcast called for " + intent.getAction());
             synchronized (mBroadcastReceiversByAction) {
@@ -605,7 +625,7 @@
         }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), any());
 
         try {
-            doReturn(mPackageInfo).when(mPackageManager).getPackageInfoAsUser(any(), anyInt(),
+            doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(nullable(String.class),
                     anyInt());
         } catch (NameNotFoundException e) {
         }
@@ -614,10 +634,19 @@
                 invocation -> mSystemFeatures.contains((String) invocation.getArgument(0)))
                 .when(mPackageManager).hasSystemFeature(any());
 
+        try {
+            doReturn(mResources).when(mPackageManager).getResourcesForApplication(anyString());
+        } catch (NameNotFoundException ex) {
+            Log.d(TAG, "NameNotFoundException: " + ex);
+        }
+
         doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
         //doReturn(mBundle).when(mCarrierConfigManager).getConfig(anyInt());
         doReturn(mBundle).when(mCarrierConfigManager).getConfig();
 
+        doReturn(mock(Network.class)).when(mConnectivityManager).registerNetworkAgent(
+                any(), any(), any(), any(), anyInt(), any(), anyInt());
+
         doReturn(true).when(mEuiccManager).isEnabled();
 
         mConfiguration.locale = Locale.US;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
index b8b5949..6a7e2ed 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
@@ -22,17 +22,18 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.os.Bundle;
+import android.telephony.CellIdentityGsm;
 import android.telephony.CellInfo;
+import android.telephony.DataFailCause;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDisconnectCause;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
-import android.telephony.gsm.GsmCellLocation;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telephony.PhoneInternalInterface.DataActivityState;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -40,6 +41,7 @@
 import org.mockito.Mock;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class DefaultPhoneNotifierTest extends TelephonyTest {
@@ -164,15 +166,21 @@
 
     @Test @SmallTest
     public void testNotifyDataConnectionFailed() throws Exception {
-        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "APN_0");
-        verify(mTelephonyRegistryManager).notifyDataConnectionFailed(0, 0, "APN_0");
+        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "default", "APN_0",
+                DataFailCause.INSUFFICIENT_RESOURCES);
+        verify(mTelephonyRegistryManager).notifyPreciseDataConnectionFailed(
+                eq(0), eq(0), eq("default"), eq("APN_0"), eq(DataFailCause.INSUFFICIENT_RESOURCES));
 
-        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "APN_1");
-        verify(mTelephonyRegistryManager).notifyDataConnectionFailed(0, 0, "APN_1");
+        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "default", "APN_1",
+                DataFailCause.INSUFFICIENT_RESOURCES);
+        verify(mTelephonyRegistryManager).notifyPreciseDataConnectionFailed(
+                eq(0), eq(0), eq("default"), eq("APN_1"), eq(DataFailCause.INSUFFICIENT_RESOURCES));
 
         doReturn(1).when(mPhone).getSubId();
-        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "APN_1");
-        verify(mTelephonyRegistryManager).notifyDataConnectionFailed(1,0, "APN_1");
+        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "default", "APN_1",
+                DataFailCause.INSUFFICIENT_RESOURCES);
+        verify(mTelephonyRegistryManager).notifyPreciseDataConnectionFailed(
+                eq(1), eq(0), eq("default"), eq("APN_1"), eq(DataFailCause.INSUFFICIENT_RESOURCES));
     }
 
     @Test @SmallTest
@@ -237,37 +245,25 @@
     @Test @SmallTest
     public void testNotifyCellLocation() throws Exception {
         // mock gsm cell location
-        GsmCellLocation mGsmCellLocation = new GsmCellLocation();
-        mGsmCellLocation.setLacAndCid(2, 3);
-        doReturn(mGsmCellLocation).when(mPhone).getCellLocation();
-        ArgumentCaptor<Bundle> cellLocationCapture =
-                ArgumentCaptor.forClass(Bundle.class);
+        CellIdentityGsm mGsmCellLocation = new CellIdentityGsm(
+                2, 3, 0, 0, null, null, null, null, Collections.emptyList());
+        doReturn(mGsmCellLocation).when(mPhone).getCellIdentity();
+        ArgumentCaptor<CellIdentityGsm> cellLocationCapture =
+                ArgumentCaptor.forClass(CellIdentityGsm.class);
 
         mDefaultPhoneNotifierUT.notifyCellLocation(mPhone, mGsmCellLocation);
         verify(mTelephonyRegistryManager).notifyCellLocation(eq(0),
                 cellLocationCapture.capture());
-        assertEquals(2, cellLocationCapture.getValue().getInt("lac"));
-        assertEquals(3, cellLocationCapture.getValue().getInt("cid"));
-        assertEquals(-1, cellLocationCapture.getValue().getInt("psc"));
+        assertEquals(2, cellLocationCapture.getValue().asCellLocation().getLac());
+        assertEquals(3, cellLocationCapture.getValue().asCellLocation().getCid());
+        assertEquals(-1, cellLocationCapture.getValue().asCellLocation().getPsc());
 
         doReturn(1).when(mPhone).getSubId();
-        mGsmCellLocation.setPsc(5);
         mDefaultPhoneNotifierUT.notifyCellLocation(mPhone, mGsmCellLocation);
         verify(mTelephonyRegistryManager).notifyCellLocation(eq(1),
                 cellLocationCapture.capture());
-        assertEquals(2, cellLocationCapture.getValue().getInt("lac"));
-        assertEquals(3, cellLocationCapture.getValue().getInt("cid"));
-        assertEquals(5, cellLocationCapture.getValue().getInt("psc"));
-    }
-
-    @Test @SmallTest
-    public void testNotifyOtaspChanged() throws Exception {
-        mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, TelephonyManager.OTASP_NEEDED);
-        verify(mTelephonyRegistryManager).notifyOtaspChanged(eq(mPhone.getSubId()),
-                eq(TelephonyManager.OTASP_NEEDED));
-
-        mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, TelephonyManager.OTASP_UNKNOWN);
-        verify(mTelephonyRegistryManager).notifyOtaspChanged(eq(mPhone.getSubId()),
-                eq(TelephonyManager.OTASP_UNKNOWN));
+        assertEquals(2, cellLocationCapture.getValue().asCellLocation().getLac());
+        assertEquals(3, cellLocationCapture.getValue().asCellLocation().getCid());
+        assertEquals(-1, cellLocationCapture.getValue().asCellLocation().getPsc());
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index b0f9cec..0133946 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -62,7 +62,7 @@
         super.tearDown();
     }
 
-    @FlakyTest
+    @Test @FlakyTest
     public void testTethering() {
         // Turn tethering on
         Intent intent = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
@@ -86,7 +86,7 @@
                 eq(true), nullable(Message.class));
     }
 
-    @FlakyTest
+    @Test @FlakyTest
     public void testCharging() {
         // Charging
         Intent intent = new Intent(BatteryManager.ACTION_CHARGING);
@@ -111,7 +111,7 @@
                 eq(false), nullable(Message.class));
     }
 
-    @FlakyTest
+    @Test @FlakyTest
     public void testReset() {
         mDSM.obtainMessage(6).sendToTarget();
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index a9e4ed0..bf9c2fc 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -25,7 +25,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.BaseColumns;
-import android.telephony.SubscriptionManager;
+import android.provider.Telephony;
 import android.test.mock.MockContentProvider;
 import android.util.Log;
 
@@ -52,66 +52,68 @@
         // This should always be consistent with TelephonyProvider#getStringForSimInfoTableCreation.
         private String getStringForSimInfoTableCreation(String tableName) {
             return "CREATE TABLE " + tableName + "("
-                    + SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
+                    + Telephony.SimInfo.UNIQUE_KEY_SUBSCRIPTION_ID
                     + " INTEGER PRIMARY KEY AUTOINCREMENT,"
-                    + SubscriptionManager.ICC_ID + " TEXT NOT NULL,"
-                    + SubscriptionManager.SIM_SLOT_INDEX
-                    + " INTEGER DEFAULT " + SubscriptionManager.SIM_NOT_INSERTED + ","
-                    + SubscriptionManager.DISPLAY_NAME + " TEXT,"
-                    + SubscriptionManager.CARRIER_NAME + " TEXT,"
-                    + SubscriptionManager.NAME_SOURCE
-                    + " INTEGER DEFAULT " + SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE + ","
-                    + SubscriptionManager.COLOR + " INTEGER DEFAULT "
-                    + SubscriptionManager.COLOR_DEFAULT + ","
-                    + SubscriptionManager.NUMBER + " TEXT,"
-                    + SubscriptionManager.DISPLAY_NUMBER_FORMAT
+                    + Telephony.SimInfo.ICC_ID + " TEXT NOT NULL,"
+                    + Telephony.SimInfo.SIM_SLOT_INDEX
+                    + " INTEGER DEFAULT " + Telephony.SimInfo.SIM_NOT_INSERTED + ","
+                    + Telephony.SimInfo.DISPLAY_NAME + " TEXT,"
+                    + Telephony.SimInfo.CARRIER_NAME + " TEXT,"
+                    + Telephony.SimInfo.NAME_SOURCE
+                    + " INTEGER DEFAULT " + Telephony.SimInfo.NAME_SOURCE_DEFAULT + ","
+                    + Telephony.SimInfo.COLOR + " INTEGER DEFAULT "
+                    + Telephony.SimInfo.COLOR_DEFAULT + ","
+                    + Telephony.SimInfo.NUMBER + " TEXT,"
+                    + Telephony.SimInfo.DISPLAY_NUMBER_FORMAT
                     + " INTEGER NOT NULL DEFAULT "
-                    + SubscriptionManager.DISPLAY_NUMBER_DEFAULT + ","
-                    + SubscriptionManager.DATA_ROAMING
-                    + " INTEGER DEFAULT " + SubscriptionManager.DATA_ROAMING_DEFAULT + ","
-                    + SubscriptionManager.MCC + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.MNC + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.MCC_STRING + " TEXT,"
-                    + SubscriptionManager.MNC_STRING + " TEXT,"
-                    + SubscriptionManager.EHPLMNS + " TEXT,"
-                    + SubscriptionManager.HPLMNS + " TEXT,"
-                    + SubscriptionManager.SIM_PROVISIONING_STATUS
-                    + " INTEGER DEFAULT " + SubscriptionManager.SIM_PROVISIONED + ","
-                    + SubscriptionManager.IS_EMBEDDED + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.CARD_ID + " TEXT NOT NULL,"
-                    + SubscriptionManager.ACCESS_RULES + " BLOB,"
-                    + SubscriptionManager.IS_REMOVABLE + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.CB_EXTREME_THREAT_ALERT + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.CB_SEVERE_THREAT_ALERT + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.CB_AMBER_ALERT + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.CB_EMERGENCY_ALERT + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.CB_ALERT_SOUND_DURATION + " INTEGER DEFAULT 4,"
-                    + SubscriptionManager.CB_ALERT_REMINDER_INTERVAL + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.CB_ALERT_VIBRATE + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.CB_ALERT_SPEECH + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.CB_ETWS_TEST_ALERT + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.CB_CHANNEL_50_ALERT + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.CB_CMAS_TEST_ALERT + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.CB_OPT_OUT_DIALOG + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.ENHANCED_4G_MODE_ENABLED + " INTEGER DEFAULT -1,"
-                    + SubscriptionManager.VT_IMS_ENABLED + " INTEGER DEFAULT -1,"
-                    + SubscriptionManager.WFC_IMS_ENABLED + " INTEGER DEFAULT -1,"
-                    + SubscriptionManager.WFC_IMS_MODE + " INTEGER DEFAULT -1,"
-                    + SubscriptionManager.WFC_IMS_ROAMING_MODE + " INTEGER DEFAULT -1,"
-                    + SubscriptionManager.WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1,"
-                    + SubscriptionManager.IS_OPPORTUNISTIC + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.GROUP_UUID + " TEXT,"
-                    + SubscriptionManager.IS_METERED + " INTEGER DEFAULT 1,"
-                    + SubscriptionManager.ISO_COUNTRY_CODE + " TEXT,"
-                    + SubscriptionManager.CARRIER_ID + " INTEGER DEFAULT -1,"
-                    + SubscriptionManager.PROFILE_CLASS
-                    + " INTEGER DEFAULT " + SubscriptionManager.PROFILE_CLASS_DEFAULT + ","
-                    + SubscriptionManager.SUBSCRIPTION_TYPE + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.WHITE_LISTED_APN_DATA + " INTEGER DEFAULT 0,"
-                    + SubscriptionManager.GROUP_OWNER + " TEXT,"
-                    + SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES + " TEXT,"
-                    + SubscriptionManager.IMSI + " TEXT,"
-                    + SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS + " BLOB"
+                    + Telephony.SimInfo.DISPLAY_NUMBER_DEFAULT + ","
+                    + Telephony.SimInfo.DATA_ROAMING
+                    + " INTEGER DEFAULT " + Telephony.SimInfo.DATA_ROAMING_DEFAULT + ","
+                    + Telephony.SimInfo.MCC + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.MNC + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.MCC_STRING + " TEXT,"
+                    + Telephony.SimInfo.MNC_STRING + " TEXT,"
+                    + Telephony.SimInfo.EHPLMNS + " TEXT,"
+                    + Telephony.SimInfo.HPLMNS + " TEXT,"
+                    + Telephony.SimInfo.SIM_PROVISIONING_STATUS
+                    + " INTEGER DEFAULT " + Telephony.SimInfo.SIM_PROVISIONED + ","
+                    + Telephony.SimInfo.IS_EMBEDDED + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.CARD_ID + " TEXT NOT NULL,"
+                    + Telephony.SimInfo.ACCESS_RULES + " BLOB,"
+                    + Telephony.SimInfo.IS_REMOVABLE + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.CB_EXTREME_THREAT_ALERT + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.CB_SEVERE_THREAT_ALERT + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.CB_AMBER_ALERT + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.CB_EMERGENCY_ALERT + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.CB_ALERT_SOUND_DURATION + " INTEGER DEFAULT 4,"
+                    + Telephony.SimInfo.CB_ALERT_REMINDER_INTERVAL + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.CB_ALERT_VIBRATE + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.CB_ALERT_SPEECH + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.CB_ETWS_TEST_ALERT + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.CB_CHANNEL_50_ALERT + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.CB_CMAS_TEST_ALERT + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.CB_OPT_OUT_DIALOG + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.ENHANCED_4G_MODE_ENABLED + " INTEGER DEFAULT -1,"
+                    + Telephony.SimInfo.VT_IMS_ENABLED + " INTEGER DEFAULT -1,"
+                    + Telephony.SimInfo.WFC_IMS_ENABLED + " INTEGER DEFAULT -1,"
+                    + Telephony.SimInfo.WFC_IMS_MODE + " INTEGER DEFAULT -1,"
+                    + Telephony.SimInfo.WFC_IMS_ROAMING_MODE + " INTEGER DEFAULT -1,"
+                    + Telephony.SimInfo.WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1,"
+                    + Telephony.SimInfo.IS_OPPORTUNISTIC + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.GROUP_UUID + " TEXT,"
+                    + Telephony.SimInfo.IS_METERED + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.ISO_COUNTRY_CODE + " TEXT,"
+                    + Telephony.SimInfo.CARRIER_ID + " INTEGER DEFAULT -1,"
+                    + Telephony.SimInfo.PROFILE_CLASS
+                    + " INTEGER DEFAULT " + Telephony.SimInfo.PROFILE_CLASS_DEFAULT + ","
+                    + Telephony.SimInfo.SUBSCRIPTION_TYPE + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.GROUP_OWNER + " TEXT,"
+                    + Telephony.SimInfo.DATA_ENABLED_OVERRIDE_RULES + " TEXT,"
+                    + Telephony.SimInfo.IMSI + " TEXT,"
+                    + Telephony.SimInfo.ACCESS_RULES_FROM_CARRIER_CONFIGS + " BLOB,"
+                    + Telephony.SimInfo.UICC_APPLICATIONS_ENABLED + " INTEGER DEFAULT 1,"
+                    + Telephony.SimInfo.ALLOWED_NETWORK_TYPES + " BIGINT DEFAULT -1, "
+                    + Telephony.SimInfo.IMS_RCS_UCE_ENABLED + " INTEGER DEFAULT 0"
                     + ");";
         }
 
@@ -134,7 +136,7 @@
     public Uri insert(Uri uri, ContentValues values) {
         SQLiteDatabase db = mDbHelper.getWritableDatabase();
         long id = db.insert("siminfo", null, values);
-        return ContentUris.withAppendedId(SubscriptionManager.CONTENT_URI, id);
+        return ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, id);
     }
 
     @Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 5c09525..7221552 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -18,12 +18,15 @@
 
 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
+import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED;
+import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_CHANGED;
 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
 
 import static org.junit.Assert.assertEquals;
 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 +36,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;
@@ -51,13 +55,13 @@
 import android.preference.PreferenceManager;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CarrierConfigManager;
-import android.telephony.CellLocation;
+import android.telephony.CellIdentity;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.telephony.cdma.CdmaCellLocation;
-import android.telephony.gsm.GsmCellLocation;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -66,6 +70,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 +94,10 @@
 public class GsmCdmaPhoneTest extends TelephonyTest {
     @Mock
     private Handler mTestHandler;
+    @Mock
+    private UiccSlot mUiccSlot;
+    @Mock
+    private CommandsInterface mMockCi;
 
     //mPhoneUnderTest
     private GsmCdmaPhone mPhoneUT;
@@ -158,14 +167,6 @@
     public void testGetMergedServiceState() throws Exception {
         ServiceState imsServiceState = new ServiceState();
 
-        NetworkRegistrationInfo imsCsWwanRegInfo = new NetworkRegistrationInfo.Builder()
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(
-                        NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .build();
-
         NetworkRegistrationInfo imsPsWwanRegInfo = new NetworkRegistrationInfo.Builder()
                 .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                 .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
@@ -182,10 +183,11 @@
                         NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                 .build();
 
-        imsServiceState.addNetworkRegistrationInfo(imsCsWwanRegInfo);
+        // Only PS states are tracked for IMS.
         imsServiceState.addNetworkRegistrationInfo(imsPsWwanRegInfo);
         imsServiceState.addNetworkRegistrationInfo(imsPsWlanRegInfo);
 
+        // Voice reg state in this case is whether or not IMS is registered.
         imsServiceState.setVoiceRegState(ServiceState.STATE_IN_SERVICE);
         imsServiceState.setDataRegState(ServiceState.STATE_IN_SERVICE);
         imsServiceState.setIwlanPreferred(true);
@@ -231,11 +233,93 @@
 
         ServiceState mergedServiceState = mPhoneUT.getServiceState();
 
-        assertEquals(ServiceState.STATE_IN_SERVICE, mergedServiceState.getVoiceRegState());
-        assertEquals(ServiceState.STATE_IN_SERVICE, mergedServiceState.getDataRegState());
+        assertEquals(ServiceState.STATE_IN_SERVICE, mergedServiceState.getState());
+        assertEquals(ServiceState.STATE_IN_SERVICE, mergedServiceState.getDataRegistrationState());
         assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, mergedServiceState.getDataNetworkType());
     }
 
+    /**
+     * Some vendors do not provide a voice registration for LTE when attached to LTE only (no CSFB
+     * available). In this case, we should still get IN_SERVICE for voice service state, since
+     * IMS is registered.
+     */
+    @Test
+    @SmallTest
+    public void testGetMergedServiceStateNoCsfb() throws Exception {
+        ServiceState imsServiceState = new ServiceState();
+
+        NetworkRegistrationInfo imsPsWwanRegInfo = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+                .setRegistrationState(
+                        NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+                .build();
+
+        NetworkRegistrationInfo imsPsWlanRegInfo = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
+                .setRegistrationState(
+                        NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING)
+                .build();
+
+        // Only PS states are tracked for IMS.
+        imsServiceState.addNetworkRegistrationInfo(imsPsWwanRegInfo);
+        imsServiceState.addNetworkRegistrationInfo(imsPsWlanRegInfo);
+
+        // Voice reg state in this case is whether or not IMS is registered.
+        imsServiceState.setVoiceRegState(ServiceState.STATE_IN_SERVICE);
+        imsServiceState.setDataRegState(ServiceState.STATE_IN_SERVICE);
+        imsServiceState.setIwlanPreferred(true);
+        doReturn(imsServiceState).when(mImsPhone).getServiceState();
+
+        replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone);
+
+        ServiceState serviceState = new ServiceState();
+
+        NetworkRegistrationInfo csWwanRegInfo = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UNKNOWN)
+                .setRegistrationState(
+                        NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING)
+                .build();
+
+        NetworkRegistrationInfo psWwanRegInfo = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+                .setRegistrationState(
+                        NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+                .build();
+
+        NetworkRegistrationInfo psWlanRegInfo = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
+                .setRegistrationState(
+                        NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING)
+                .build();
+
+        serviceState.addNetworkRegistrationInfo(csWwanRegInfo);
+        serviceState.addNetworkRegistrationInfo(psWwanRegInfo);
+        serviceState.addNetworkRegistrationInfo(psWlanRegInfo);
+        // No CSFB, voice is OOS for LTE only attach
+        serviceState.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+        serviceState.setDataRegState(ServiceState.STATE_IN_SERVICE);
+        serviceState.setIwlanPreferred(true);
+
+        mSST.mSS = serviceState;
+        mPhoneUT.mSST = mSST;
+
+        ServiceState mergedServiceState = mPhoneUT.getServiceState();
+
+        assertEquals(ServiceState.STATE_IN_SERVICE, mergedServiceState.getState());
+        assertEquals(ServiceState.STATE_IN_SERVICE, mergedServiceState.getDataRegistrationState());
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, mergedServiceState.getDataNetworkType());
+    }
+
     @Test
     @SmallTest
     public void testGetSubscriberIdForGsmPhone() {
@@ -291,20 +375,20 @@
     @SmallTest
     public void testGetCellLocation() {
         // GSM
-        CellLocation cellLocation = new GsmCellLocation();
+        CellIdentity cellLocation = new CellIdentityGsm();
         WorkSource workSource = new WorkSource(Process.myUid(),
             mContext.getPackageName());
-        doReturn(cellLocation).when(mSST).getCellLocation();
-        assertEquals(cellLocation, mPhoneUT.getCellLocation());
+        doReturn(cellLocation).when(mSST).getCellIdentity();
+        assertEquals(cellLocation, mPhoneUT.getCellIdentity());
 
         // Switch to CDMA
         switchToCdma();
 
-        CdmaCellLocation cdmaCellLocation = new CdmaCellLocation();
-        doReturn(cdmaCellLocation).when(mSST).getCellLocation();
+        CellIdentityCdma cdmaCellLocation = new CellIdentityCdma();
+        doReturn(cdmaCellLocation).when(mSST).getCellIdentity();
 
-        CdmaCellLocation actualCellLocation =
-                (CdmaCellLocation) mPhoneUT.getCellLocation();
+        CellIdentityCdma actualCellLocation =
+                (CellIdentityCdma) mPhoneUT.getCellIdentity();
 
         assertEquals(actualCellLocation, cdmaCellLocation);
     }
@@ -1122,4 +1206,120 @@
                 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));
+    }
+
+    @Test
+    @SmallTest
+    public void testReapplyUiccApplicationEnablementNotNeeded() throws Exception {
+        mPhoneUT.mCi = mMockCi;
+        // UiccSlot is null, or not present, or mUiccApplicationsEnabled is not available, or IccId
+        // is not available, Doing nothing.
+        doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt());
+        Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget();
+        processAllMessages();
+        doReturn(IccCardStatus.CardState.CARDSTATE_ABSENT).when(mUiccSlot).getCardState();
+        Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget();
+        processAllMessages();
+        doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState();
+        Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget();
+        Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED,
+                new AsyncResult(null, true, null)).sendToTarget();
+        processAllMessages();
+        verify(mSubscriptionController, never()).getSubInfoForIccId(any());
+
+        // Have IccId defined. But expected value and current value are the same. So no RIL command
+        // should be sent.
+        String iccId = "Fake iccId";
+        doReturn(iccId).when(mUiccSlot).getIccId();
+        Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget();
+        processAllMessages();
+        verify(mSubscriptionController).getSubInfoForIccId(iccId);
+        verify(mMockCi, never()).enableUiccApplications(anyBoolean(), any());
+    }
+
+    @Test
+    @SmallTest
+    public void testReapplyUiccApplicationEnablementSuccess() throws Exception {
+        mPhoneUT.mCi = mMockCi;
+        // Set SIM to be present, with a fake iccId, and notify enablement being false.
+        doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt());
+        doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState();
+        String iccId = "Fake iccId";
+        doReturn(iccId).when(mUiccSlot).getIccId();
+        Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED,
+                new AsyncResult(null, false, null)).sendToTarget();
+        processAllMessages();
+
+        // Should try to enable uicc applications as by default hey are expected to be true.
+        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mMockCi, times(1)).enableUiccApplications(eq(true), messageCaptor.capture());
+        // Send message back with no exception.
+        AsyncResult.forMessage(messageCaptor.getValue(), null, null);
+        messageCaptor.getValue().sendToTarget();
+        processAllMessages();
+
+        // There shouldn't be any retry message.
+        moveTimeForward(5000);
+        processAllMessages();
+        verify(mMockCi, times(1)).enableUiccApplications(eq(true), any());
+    }
+
+    // TODO: b/146181737 uncomment below test.
+//    @Test
+//    @SmallTest
+//    public void testReapplyUiccApplicationEnablementRetry() throws Exception {
+//        mPhoneUT.mCi = mMockCi;
+//        // Set SIM to be present, with a fake iccId, and notify enablement being false.
+//        doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt());
+//        doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState();
+//        String iccId = "Fake iccId";
+//        doReturn(iccId).when(mUiccSlot).getIccId();
+//        Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED,
+//                new AsyncResult(null, false, null)).sendToTarget();
+//        processAllMessages();
+//
+//        // Should try to enable uicc applications as by default hey are expected to be true.
+//        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+//        verify(mMockCi).enableUiccApplications(eq(true), messageCaptor.capture());
+//        clearInvocations(mMockCi);
+//        // Send message back with SIM_BUSY exception. Should retry.
+//        AsyncResult.forMessage(messageCaptor.getValue(), null, new CommandException(
+//                CommandException.Error.SIM_BUSY));
+//        messageCaptor.getValue().sendToTarget();
+//        processAllMessages();
+//        // There should be a retry message.
+//        moveTimeForward(5000);
+//        processAllMessages();
+//        verify(mMockCi).enableUiccApplications(eq(true), messageCaptor.capture());
+//        clearInvocations(mMockCi);
+//
+//        // Send message back with NOT_SUPPORTED exception. Should retry.
+//        AsyncResult.forMessage(messageCaptor.getValue(), null, new CommandException(
+//                CommandException.Error.REQUEST_NOT_SUPPORTED));
+//        messageCaptor.getValue().sendToTarget();
+//        processAllMessages();
+//        // There should not be a retry message.
+//        moveTimeForward(5000);
+//        processAllMessages();
+//        verify(mMockCi, never()).enableUiccApplications(eq(true), messageCaptor.capture());
+//    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
index ad5d0ab..3d4ef03 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
@@ -56,6 +56,15 @@
     }
 
     @SmallTest
+    public void testIsEmailAddress() throws Exception {
+        assertTrue(SmsMessage.isEmailAddress("\"First Last\" <name@example.com>"));
+        assertTrue(SmsMessage.isEmailAddress("FirstLast <name@sub.example.com>"));
+        assertFalse(SmsMessage.isEmailAddress("FirstLast 1112223333"));
+        assertFalse(SmsMessage.isEmailAddress(""));
+        assertFalse(SmsMessage.isEmailAddress("nmg5gj945j"));
+    }
+
+    @SmallTest
     public void testUdh() throws Exception {
         String pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F"
                 + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D"
diff --git a/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
index 5d69ab6..19bf186 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
@@ -80,7 +80,7 @@
         mCellInfo.setCellIdentity(new CellIdentityGsm(
                     CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
                     CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
-                    US_MCC, FAKE_MNC, null, null));
+                    US_MCC, FAKE_MNC, null, null, Collections.emptyList()));
         doAnswer(invocation -> {
             Message m = invocation.getArgument(1);
             AsyncResult.forMessage(m, Arrays.asList(mCellInfo), null);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
index d195c2e..fcffa96 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
@@ -16,77 +16,105 @@
 
 package com.android.internal.telephony;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import org.junit.Ignore;
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.telephony.MccTable.MccMnc;
+import com.android.internal.telephony.util.LocaleUtils;
+
+import org.junit.Test;
 
 import java.util.Locale;
 
-// TODO try using InstrumentationRegistry.getContext() instead of the default
-// AndroidTestCase context
-public class MccTableTest extends AndroidTestCase {
-    private final static String LOG_TAG = "GSM";
+public class MccTableTest {
 
     @SmallTest
-    @Ignore
-    public void testCountryCode() throws Exception {
-        assertEquals("lu", MccTable.countryCodeForMcc(270));
-        assertEquals("gr", MccTable.countryCodeForMcc(202));
-        assertEquals("fk", MccTable.countryCodeForMcc(750));
-        assertEquals("mg", MccTable.countryCodeForMcc(646));
-        assertEquals("us", MccTable.countryCodeForMcc(314));
-        assertEquals("", MccTable.countryCodeForMcc(300));  // mcc not defined, hence default
-        assertEquals("", MccTable.countryCodeForMcc(0));    // mcc not defined, hence default
-        assertEquals("", MccTable.countryCodeForMcc(2000)); // mcc not defined, hence default
+    @Test
+    public void testCountryCodeForMcc() throws Exception {
+        checkMccLookupWithNoMnc("lu", 270);
+        checkMccLookupWithNoMnc("gr", 202);
+        checkMccLookupWithNoMnc("fk", 750);
+        checkMccLookupWithNoMnc("mg", 646);
+        checkMccLookupWithNoMnc("us", 314);
+        checkMccLookupWithNoMnc("", 300);  // mcc not defined, hence default
+        checkMccLookupWithNoMnc("", 0);    // mcc not defined, hence default
+        checkMccLookupWithNoMnc("", 2000); // mcc not defined, hence default
+    }
+
+    private void checkMccLookupWithNoMnc(String expectedCountryIsoCode, int mcc) {
+        assertEquals(expectedCountryIsoCode, MccTable.countryCodeForMcc(mcc));
+        assertEquals(expectedCountryIsoCode, MccTable.countryCodeForMcc(mcc));
+        assertEquals(expectedCountryIsoCode, MccTable.countryCodeForMcc("" + mcc));
+        assertEquals(expectedCountryIsoCode,
+                MccTable.geoCountryCodeForMccMnc(new MccMnc("" + mcc, "999")));
     }
 
     @SmallTest
-    @Ignore
+    @Test
+    public void testGeoCountryCodeForMccMnc() throws Exception {
+        // This test is possibly fragile as this data is configurable.
+        assertEquals("gu", MccTable.geoCountryCodeForMccMnc(new MccMnc("310", "370")));
+    }
+
+    @SmallTest
+    @Test
     public void testLang() throws Exception {
-        assertEquals("en", MccTable.defaultLanguageForMcc(311));
-        assertEquals("de", MccTable.defaultLanguageForMcc(232));
-        assertEquals("cs", MccTable.defaultLanguageForMcc(230));
-        assertEquals("nl", MccTable.defaultLanguageForMcc(204));
-        assertEquals("is", MccTable.defaultLanguageForMcc(274));
-        assertEquals(null, MccTable.defaultLanguageForMcc(0));    // mcc not defined, hence default
-        assertEquals(null, MccTable.defaultLanguageForMcc(2000)); // mcc not defined, hence default
+        assertEquals("en", LocaleUtils.defaultLanguageForMcc(311));
+        assertEquals("de", LocaleUtils.defaultLanguageForMcc(232));
+        assertEquals("cs", LocaleUtils.defaultLanguageForMcc(230));
+        assertEquals("nl", LocaleUtils.defaultLanguageForMcc(204));
+        assertEquals("is", LocaleUtils.defaultLanguageForMcc(274));
+        // mcc not defined, hence default
+        assertEquals(null, LocaleUtils.defaultLanguageForMcc(0));
+        // mcc not defined, hence default
+        assertEquals(null, LocaleUtils.defaultLanguageForMcc(2000));
     }
 
     @SmallTest
-    @Ignore
+    @Test
     public void testLang_India() throws Exception {
-        assertEquals("en", MccTable.defaultLanguageForMcc(404));
-        assertEquals("en", MccTable.defaultLanguageForMcc(405));
-        assertEquals("en", MccTable.defaultLanguageForMcc(406));
+        assertEquals("en", LocaleUtils.defaultLanguageForMcc(404));
+        assertEquals("en", LocaleUtils.defaultLanguageForMcc(405));
+        assertEquals("en", LocaleUtils.defaultLanguageForMcc(406));
     }
 
     @SmallTest
-    @Ignore
+    @Test
     public void testLocale() throws Exception {
         assertEquals(Locale.forLanguageTag("en-CA"),
-                MccTable.getLocaleFromMcc(getContext(), 302, null));
+                LocaleUtils.getLocaleFromMcc(getContext(), 302, null));
         assertEquals(Locale.forLanguageTag("en-GB"),
-                MccTable.getLocaleFromMcc(getContext(), 234, null));
+                LocaleUtils.getLocaleFromMcc(getContext(), 234, null));
         assertEquals(Locale.forLanguageTag("en-US"),
-                MccTable.getLocaleFromMcc(getContext(), 0, "en"));
+                LocaleUtils.getLocaleFromMcc(getContext(), 0, "en"));
         assertEquals(Locale.forLanguageTag("zh-HK"),
-                MccTable.getLocaleFromMcc(getContext(), 454, null));
+                LocaleUtils.getLocaleFromMcc(getContext(), 454, null));
         assertEquals(Locale.forLanguageTag("en-HK"),
-                MccTable.getLocaleFromMcc(getContext(), 454, "en"));
+                LocaleUtils.getLocaleFromMcc(getContext(), 454, "en"));
         assertEquals(Locale.forLanguageTag("zh-TW"),
-                MccTable.getLocaleFromMcc(getContext(), 466, null));
+                LocaleUtils.getLocaleFromMcc(getContext(), 466, null));
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getContext();
     }
 
     @SmallTest
-    @Ignore
+    @Test
     public void testSmDigits() throws Exception {
         assertEquals(3, MccTable.smallestDigitsMccForMnc(312));
         assertEquals(2, MccTable.smallestDigitsMccForMnc(430));
         assertEquals(3, MccTable.smallestDigitsMccForMnc(365));
         assertEquals(2, MccTable.smallestDigitsMccForMnc(536));
-        assertEquals(2, MccTable.smallestDigitsMccForMnc(352));  // sd not defined, hence default
-        assertEquals(2, MccTable.smallestDigitsMccForMnc(0));    // mcc not defined, hence default
-        assertEquals(2, MccTable.smallestDigitsMccForMnc(2000)); // mcc not defined, hence default
+        // sd not defined, hence default
+        assertEquals(2, MccTable.smallestDigitsMccForMnc(352));
+        // mcc not defined, hence default
+        assertEquals(2, MccTable.smallestDigitsMccForMnc(0));
+        // mcc not defined, hence default
+        assertEquals(2, MccTable.smallestDigitsMccForMnc(2000));
     }
 }
diff --git a/src/java/com/android/internal/telephony/test/ModelInterpreter.java b/tests/telephonytests/src/com/android/internal/telephony/ModelInterpreter.java
similarity index 98%
rename from src/java/com/android/internal/telephony/test/ModelInterpreter.java
rename to tests/telephonytests/src/com/android/internal/telephony/ModelInterpreter.java
index 2a046d9..ddb99d9 100644
--- a/src/java/com/android/internal/telephony/test/ModelInterpreter.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ModelInterpreter.java
@@ -16,11 +16,11 @@
 
 package com.android.internal.telephony.test;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.HandlerThread;
 import android.os.Looper;
-import android.telephony.Rlog;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import com.android.telephony.Rlog;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ModemInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/ModemInfoTest.java
deleted file mode 100644
index 6e646d5..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/ModemInfoTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 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 org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.os.Parcel;
-import android.telephony.ModemInfo;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-public class ModemInfoTest {
-    @Test
-    @SmallTest
-    public void basicTests() throws Exception {
-        int modemId = 1;
-        int rat = 2;
-        boolean isVoiceSupported = true;
-        boolean isDataSupported = false;
-        ModemInfo modemInfo = new ModemInfo(modemId, rat, isVoiceSupported, isDataSupported);
-
-        assertEquals(modemId, modemInfo.modemId);
-        assertEquals(rat, modemInfo.rat);
-        assertEquals(isVoiceSupported, modemInfo.isVoiceSupported);
-        assertEquals(isDataSupported, modemInfo.isDataSupported);
-        assertNotEquals(modemInfo, new ModemInfo(
-                modemId + 1, rat, isVoiceSupported, isDataSupported));
-        assertNotEquals(modemInfo, new ModemInfo(
-                modemId, rat + 1, isVoiceSupported, isDataSupported));
-        assertNotEquals(modemInfo, new ModemInfo(modemId, rat, !isVoiceSupported, isDataSupported));
-        assertNotEquals(modemInfo, new ModemInfo(modemId, rat, isVoiceSupported, !isDataSupported));
-    }
-
-    @Test
-    @SmallTest
-    public void parcelReadWrite() throws Exception {
-        int modemId = 1;
-        int rat = 2;
-        boolean isVoiceSupported = true;
-        boolean isDataSupported = false;
-        ModemInfo modemInfo = new ModemInfo(modemId, rat, isVoiceSupported, isDataSupported);
-
-        Parcel parcel = Parcel.obtain();
-        modemInfo.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        ModemInfo toCompare = ModemInfo.CREATOR.createFromParcel(parcel);
-
-        assertEquals(modemId, toCompare.modemId);
-        assertEquals(rat, toCompare.rat);
-        assertEquals(isVoiceSupported, toCompare.isVoiceSupported);
-        assertEquals(isDataSupported, toCompare.isDataSupported);
-        assertEquals(modemInfo, toCompare);
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
index 0a920a9..d6db30e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
@@ -86,19 +87,19 @@
             "T-mobile", 0, 255, "12345", 0, null, "310", "260",
             "156", false, null, null, -1, false, mGroupUuid1.toString(), false,
             TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT,
-            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
+            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
 
     private SubscriptionInfo mSubInfo3 = new SubscriptionInfo(3, "subInfo3 IccId", -1, "T-mobile",
             "T-mobile", 0, 255, "12345", 0, null, "310", "260",
             "156", false, null, null, -1, false, mGroupUuid1.toString(), false,
             TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT,
-            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
+            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
 
     private SubscriptionInfo mSubInfo4 = new SubscriptionInfo(4, "subInfo4 IccId", -1, "T-mobile",
             "T-mobile", 0, 255, "12345", 0, null, "310", "260",
             "156", false, null, null, -1, false, mGroupUuid1.toString(), false,
             TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT,
-            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null);
+            SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true);
 
     @Before
     public void setUp() throws Exception {
@@ -121,7 +122,7 @@
         doReturn(2).when(mPhoneMock2).getSubId();
         List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo1, mSubInfo2);
         doReturn(infoList).when(mSubControllerMock)
-                .getActiveSubscriptionInfoList(anyString());
+                .getActiveSubscriptionInfoList(anyString(), nullable(String.class));
         doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         mPhones = new Phone[] {mPhoneMock1, mPhoneMock2};
@@ -163,7 +164,8 @@
         doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2);
         doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId();
         List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo1);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         // Mark subscription ready as false. The below sub info change should be ignored.
@@ -200,7 +202,8 @@
         doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2);
         doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId();
         List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo1);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded();
@@ -215,7 +218,8 @@
         doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1);
         doReturn(2).when(mPhoneMock1).getSubId();
         infoList = Arrays.asList(mSubInfo2);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
@@ -238,7 +242,8 @@
         doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2);
         doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId();
         List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo1);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded();
@@ -258,7 +263,8 @@
         doReturn(1).when(mSubControllerMock).getPhoneId(2);
         doReturn(2).when(mPhoneMock2).getSubId();
         infoList = Arrays.asList(mSubInfo1, mSubInfo2);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
@@ -280,7 +286,8 @@
         doReturn(1).when(mSubControllerMock).getPhoneId(3);
         doReturn(3).when(mPhoneMock2).getSubId();
         infoList = Arrays.asList(mSubInfo1, mSubInfo3);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
@@ -325,7 +332,8 @@
         clearInvocations(mSubControllerMock);
         doReturn(false).when(mSubControllerMock).isActiveSubId(1);
         List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo2);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
         mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
         mMultiSimSettingControllerUT.notifyCarrierConfigChanged(
@@ -361,7 +369,7 @@
         doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(3);
         doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(4);
         doReturn(Arrays.asList(mSubInfo2, mSubInfo3, mSubInfo4)).when(mSubControllerMock)
-                .getSubscriptionsInGroup(any(), anyString());
+                .getSubscriptionsInGroup(any(), anyString(), nullable(String.class));
         mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1);
         processAllMessages();
         // This should result in setting sync.
@@ -398,7 +406,8 @@
         doReturn(2).when(mSubControllerMock).getDefaultSmsSubId();
         doReturn(1).when(mSubControllerMock).getDefaultVoiceSubId();
         List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo1, mSubInfo3);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
@@ -475,7 +484,7 @@
         GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 2, false);
         // Group sub 1 with sub 2.
         doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock)
-                .getSubscriptionsInGroup(any(), anyString());
+                .getSubscriptionsInGroup(any(), anyString(), nullable(String.class));
         mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1);
         processAllMessages();
         // This should result in setting sync.
@@ -515,7 +524,7 @@
         // Create subscription grouping.
         replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1);
         doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock)
-                .getSubscriptionsInGroup(any(), anyString());
+                .getSubscriptionsInGroup(any(), anyString(), nullable(String.class));
         mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1);
         processAllMessages();
         // This should result in setting sync.
@@ -556,7 +565,8 @@
         doReturn(1).when(mSubControllerMock).getPhoneId(3);
         doReturn(3).when(mPhoneMock2).getSubId();
         List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo1, mSubInfo3);
-        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
+        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(),
+                nullable(String.class));
         doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean());
 
         // Nothing should happen until carrier config change is notified on sub 3.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
index 1b58f36..77398b2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
@@ -32,6 +32,7 @@
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /** Unit tests for {@link NetworkScanResult}. */
 public class NetworkScanResultTest {
@@ -41,7 +42,8 @@
     public void testParcel() {
         ArrayList<CellInfo> infos = new ArrayList<CellInfo>();
 
-        CellIdentityGsm cig = new CellIdentityGsm(1, 2, 40, 5, "001", "01", "test", "tst");
+        CellIdentityGsm cig = new CellIdentityGsm(1, 2, 40, 5, "001", "01", "test", "tst",
+                Collections.emptyList());
         CellSignalStrengthGsm cssg = new CellSignalStrengthGsm(5, 6, 7);
         CellInfoGsm gsm = new CellInfoGsm();
         gsm.setRegistered(true);
@@ -51,7 +53,7 @@
         infos.add(gsm);
 
         CellIdentityLte cil = new CellIdentityLte(
-                10, 5, 200, 2000, 10000, "001", "01", "test", "tst");
+                10, 5, 200, 2000, 10000, "001", "01", "test", "tst", Collections.emptyList(), null);
         CellSignalStrengthLte cssl = new CellSignalStrengthLte(15, 16, 17, 18, 19, 20);
         CellInfoLte lte = new CellInfoLte();
         lte.setRegistered(false);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineImplTest.java b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineImplTest.java
index 3702d3e..30833e3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineImplTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineImplTest.java
@@ -25,6 +25,7 @@
 import static com.android.internal.telephony.NitzStateMachineTestSupport.UNIQUE_US_ZONE_SCENARIO2;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.UNITED_KINGDOM_SCENARIO;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.US_COUNTRY_DEFAULT_ZONE_ID;
+import static com.android.internal.telephony.NitzStateMachineTestSupport.createEmptyTimeSuggestion;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.createTimeSuggestionFromNitzSignal;
 
 import static org.junit.Assert.assertEquals;
@@ -32,13 +33,13 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
 import android.icu.util.TimeZone;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
+import android.timezone.CountryTimeZones.OffsetResult;
 
 import com.android.internal.telephony.NitzStateMachineTestSupport.FakeDeviceState;
 import com.android.internal.telephony.NitzStateMachineTestSupport.Scenario;
-import com.android.internal.telephony.TimeZoneLookupHelper.OffsetResult;
 
 import org.junit.After;
 import org.junit.Before;
@@ -94,7 +95,7 @@
                 .nitzReceived(nitzSignal);
 
         // Country + NITZ is enough for both time + time zone detection.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(
                 expectedTimeSuggestion, scenario.getTimeZoneId());
@@ -102,6 +103,7 @@
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -154,7 +156,7 @@
                 .networkAvailable();
 
         script.nitzReceived(nitzSignal);
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
@@ -187,7 +189,7 @@
                 .networkAvailable();
 
         script.nitzReceived(nitzSignal);
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
@@ -213,7 +215,7 @@
                 .nitzReceived(nitzSignal);
 
         // Country + NITZ is enough for both time + time zone detection.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(
                 expectedTimeSuggestion, scenario.getTimeZoneId());
@@ -221,6 +223,7 @@
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -246,7 +249,7 @@
             script.nitzReceived(nitzSignal);
 
             // Country + NITZ is enough for both time + time zone detection.
-            PhoneTimeSuggestion expectedTimeSuggestion =
+            TelephonyTimeSuggestion expectedTimeSuggestion =
                     createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
             script.verifyTimeSuggestedAndZoneSetAndReset(
                     expectedTimeSuggestion, scenario.getTimeZoneId());
@@ -254,6 +257,7 @@
             // Check NitzStateMachine state.
             assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
             assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+            assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
         }
 
         // A valid NITZ signal for the non-default zone should still be correctly detected.
@@ -268,6 +272,7 @@
             // Check NitzStateMachine state.
             assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
             assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+            assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
         }
 
         // Demonstrate what happens with a bogus NITZ for NZ: because the default zone is boosted
@@ -285,6 +290,7 @@
             // Check NitzStateMachine state.
             assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
             assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+            assertEquals(expectedTimeZoneId, mNitzStateMachine.getSavedTimeZoneId());
         }
     }
 
@@ -310,7 +316,7 @@
             script.nitzReceived(nitzSignal);
 
             // Country + NITZ is enough for both time + time zone detection.
-            PhoneTimeSuggestion expectedTimeSuggestion =
+            TelephonyTimeSuggestion expectedTimeSuggestion =
                     createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
             script.verifyTimeSuggestedAndZoneSetAndReset(
                     expectedTimeSuggestion, scenario.getTimeZoneId());
@@ -318,6 +324,7 @@
             // Check NitzStateMachine state.
             assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
             assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+            assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
         }
 
         // A valid NITZ signal for a different zone should also be correctly detected.
@@ -332,6 +339,7 @@
             // Check NitzStateMachine state.
             assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
             assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+            assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
         }
 
         // Demonstrate what happens with a bogus NITZ for US: because the default zone is not
@@ -346,8 +354,9 @@
                     .verifyNothingWasSetAndReset();
 
             // Check NitzStateMachine state.
-            assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
+            assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
             assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+            assertNull(mNitzStateMachine.getSavedTimeZoneId());
         }
     }
 
@@ -367,13 +376,14 @@
                 .verifyNothingWasSetAndReset()
                 .nitzReceived(nitzSignal);
         // Time zone detection is disabled, but time should be suggested from NITZ.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -392,13 +402,14 @@
                 .verifyNothingWasSetAndReset()
                 .nitzReceived(nitzSignal);
         // Time zone detection is disabled, but time should be suggested from NITZ.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -416,13 +427,14 @@
         script.nitzReceived(nitzSignal);
 
         // The NITZ alone isn't enough to detect a time zone.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate the country code becoming known.
         script.countryReceived(scenario.getNetworkCountryIsoCode())
@@ -432,6 +444,7 @@
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -448,13 +461,14 @@
                 scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
         script.nitzReceived(nitzSignal);
         // The NITZ alone isn't enough to detect a time zone.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate the country code becoming known.
         script.countryReceived(scenario.getNetworkCountryIsoCode());
@@ -465,6 +479,7 @@
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -483,13 +498,14 @@
         script.nitzReceived(goodNitzSignal);
 
         // The NITZ alone isn't enough to detect a time zone.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), goodNitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(goodNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate the country code becoming known.
         script.countryReceived(scenario.getNetworkCountryIsoCode())
@@ -498,6 +514,7 @@
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(goodNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -520,13 +537,14 @@
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate receiving an NITZ signal.
         script.nitzReceived(goodNitzSignal);
 
         // The time will be suggested from the NITZ signal.
         // The combination of NITZ + country will cause the time zone to be set.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), goodNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(
                 expectedTimeSuggestion, scenario.getTimeZoneId());
@@ -534,6 +552,7 @@
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(goodNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -561,13 +580,14 @@
 
         // The NITZ alone isn't enough to detect a time zone, but there isn't enough
         // information to work out it is bogus.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), badNitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(badNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate the country code becoming known.
         script.countryReceived(scenario.getNetworkCountryIsoCode())
@@ -576,6 +596,7 @@
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(badNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -606,18 +627,20 @@
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate receiving an NITZ signal.
         script.nitzReceived(badNitzSignal);
 
         // The NITZ should be detected as bogus so only the time will be suggested.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), badNitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(badNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -644,13 +667,14 @@
         script.nitzReceived(badNitzSignal);
         // The NITZ alone isn't enough to detect a time zone, but there isn't enough
         // information to work out its bogus.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), badNitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(badNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate the country code becoming known.
         script.countryReceived(scenario.getNetworkCountryIsoCode())
@@ -661,6 +685,7 @@
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(badNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -692,18 +717,20 @@
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate receiving an NITZ signal.
         script.nitzReceived(badNitzSignal);
 
         // The NITZ should be detected as bogus so only the time will be suggested.
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), badNitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(badNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -733,13 +760,14 @@
         // Simulate receiving the emulator NITZ signal.
         script.nitzReceived(emulatorNitzSignal);
 
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), emulatorNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(expectedTimeSuggestion, emulatorTimeZoneId);
 
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(emulatorNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(emulatorTimeZoneId, mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -759,19 +787,21 @@
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate receiving the NITZ signal.
         TimestampedValue<NitzData> nitzSignal =
                 scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
         script.nitzReceived(nitzSignal);
 
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(expectedTimeSuggestion, expectedZoneId);
 
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(expectedZoneId, mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -790,13 +820,14 @@
                 scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
         script.nitzReceived(nitzSignal);
 
-        PhoneTimeSuggestion expectedTimeSuggestion =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), nitzSignal);
         script.verifyOnlyTimeWasSuggestedAndReset(expectedTimeSuggestion);
 
         // Check NitzStateMachine state.
         assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // The time zone should be set (but the country is not valid so it's unlikely to be
         // correct).
@@ -805,6 +836,7 @@
         // Check NitzStateMachine state.
         assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(nitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(expectedZoneId, mNitzStateMachine.getSavedTimeZoneId());
     }
 
     @Test
@@ -825,7 +857,7 @@
         script.nitzReceived(preflightNitzSignal)
                 .countryReceived(scenario.getNetworkCountryIsoCode());
 
-        PhoneTimeSuggestion expectedPreFlightTimeSuggestion =
+        TelephonyTimeSuggestion expectedPreFlightTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), preflightNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(
                 expectedPreFlightTimeSuggestion, scenario.getTimeZoneId());
@@ -842,7 +874,9 @@
                 .verifyOnlyTimeZoneWasSetAndReset(scenario.getTimeZoneId());
 
         // Check state that NitzStateMachine must expose.
+        assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(preflightNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
 
         // Boarded flight: Airplane mode turned on / time zone detection still enabled.
         // The NitzStateMachineImpl must lose all state and stop having an opinion about time zone.
@@ -854,11 +888,15 @@
         script.toggleAirplaneMode(true);
 
         // Check state that NitzStateMachine must expose.
+        assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Verify there's no time zone opinion by toggling auto time zone off and on.
+        TelephonyTimeSuggestion emptyTimeSuggestion =
+                createEmptyTimeSuggestion(mPhone.getPhoneId());
         script.toggleTimeZoneDetectionEnabled(false)
-                .verifyNothingWasSetAndReset()
+                .verifyOnlyTimeWasSuggestedAndReset(emptyTimeSuggestion)
                 .toggleTimeZoneDetectionEnabled(true)
                 .verifyNothingWasSetAndReset();
 
@@ -878,7 +916,9 @@
                 .verifyNothingWasSetAndReset();
 
         // Check the state that NitzStateMachine must expose.
+        assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Post flight: Device has moved and receives new signals.
 
@@ -897,13 +937,15 @@
         script.countryReceived(scenario.getNetworkCountryIsoCode())
                 .nitzReceived(postFlightNitzSignal);
 
-        PhoneTimeSuggestion expectedPostFlightTimeSuggestion =
+        TelephonyTimeSuggestion expectedPostFlightTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), postFlightNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(expectedPostFlightTimeSuggestion,
                         scenario.getTimeZoneId());
 
         // Check state that NitzStateMachine must expose.
+        assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(postFlightNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     /**
@@ -927,7 +969,7 @@
                 .nitzReceived(initialNitzSignal)
                 .countryReceived(scenario.getNetworkCountryIsoCode());
 
-        PhoneTimeSuggestion expectedInitialTimeSuggestion =
+        TelephonyTimeSuggestion expectedInitialTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), initialNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(
                 expectedInitialTimeSuggestion, scenario.getTimeZoneId());
@@ -944,19 +986,26 @@
                 .verifyOnlyTimeZoneWasSetAndReset(scenario.getTimeZoneId());
 
         // Check state that NitzStateMachine must expose.
+        assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(initialNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate losing the network. The NitzStateMachineImpl must lose all NITZ state and stop
         // having an opinion about time zone.
-        script.networkUnavailable()
-                .verifyNothingWasSetAndReset();
+        script.networkUnavailable();
+
+        TelephonyTimeSuggestion emptyTimeSuggestion =
+                createEmptyTimeSuggestion(mPhone.getPhoneId());
+        script.verifyOnlyTimeWasSuggestedAndReset(emptyTimeSuggestion);
 
         // Simulate the passage of time and update the device realtime clock.
         scenario.incrementTime(timeStepMillis);
         script.incrementTime(timeStepMillis);
 
         // Check state that NitzStateMachine must expose.
+        assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Verify there's no time zone opinion by toggling auto time zone off and on.
         script.toggleTimeZoneDetectionEnabled(false)
@@ -978,7 +1027,9 @@
                 .verifyNothingWasSetAndReset();
 
         // Check the state that NitzStateMachine must expose.
+        assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertNull(mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate the passage of time and update the device realtime clock.
         scenario.incrementTime(timeStepMillis);
@@ -990,13 +1041,15 @@
                 scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
         script.nitzReceived(finalNitzSignal);
 
-        PhoneTimeSuggestion expectedFinalTimeSuggestion =
+        TelephonyTimeSuggestion expectedFinalTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), finalNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(expectedFinalTimeSuggestion,
                         scenario.getTimeZoneId());
 
         // Check state that NitzStateMachine must expose.
+        assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(finalNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     /**
@@ -1020,7 +1073,7 @@
                 .nitzReceived(initialNitzSignal)
                 .countryReceived(scenario.getNetworkCountryIsoCode());
 
-        PhoneTimeSuggestion expectedInitialTimeSuggestion =
+        TelephonyTimeSuggestion expectedInitialTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), initialNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(
                 expectedInitialTimeSuggestion, scenario.getTimeZoneId());
@@ -1037,20 +1090,27 @@
                 .verifyOnlyTimeZoneWasSetAndReset(scenario.getTimeZoneId());
 
         // Check state that NitzStateMachine must expose.
+        assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(initialNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate losing the network. The NitzStateMachineImpl must lose all NITZ state but should
         // retain country knowledge and so remain opinionated about time zone ID because the country
         // is sufficient to detect time zone in the UK.
-        script.networkUnavailable()
-                .verifyOnlyTimeZoneWasSetAndReset(scenario.getTimeZoneId());
+        script.networkUnavailable();
+
+        TelephonyTimeSuggestion emptyTimeSuggestion =
+                createEmptyTimeSuggestion(mPhone.getPhoneId());
+        script.verifyTimeSuggestedAndZoneSetAndReset(emptyTimeSuggestion, scenario.getTimeZoneId());
 
         // Simulate the passage of time and update the device realtime clock.
         scenario.incrementTime(timeStepMillis);
         script.incrementTime(timeStepMillis);
 
         // Check state that NitzStateMachine must expose.
+        assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
 
         // Verify there's a time zone opinion by toggling auto time zone off and on.
         script.toggleTimeZoneDetectionEnabled(false)
@@ -1072,7 +1132,9 @@
                 .verifyOnlyTimeZoneWasSetAndReset(scenario.getTimeZoneId());
 
         // Check the state that NitzStateMachine must expose.
+        assertFalse(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertNull(mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
 
         // Simulate the passage of time and update the device realtime clock.
         scenario.incrementTime(timeStepMillis);
@@ -1084,13 +1146,15 @@
                 scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
         script.nitzReceived(finalNitzSignal);
 
-        PhoneTimeSuggestion expectedFinalTimeSuggestion =
+        TelephonyTimeSuggestion expectedFinalTimeSuggestion =
                 createTimeSuggestionFromNitzSignal(mPhone.getPhoneId(), finalNitzSignal);
         script.verifyTimeSuggestedAndZoneSetAndReset(expectedFinalTimeSuggestion,
                         scenario.getTimeZoneId());
 
         // Check state that NitzStateMachine must expose.
+        assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful());
         assertEquals(finalNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData());
+        assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId());
     }
 
     /**
@@ -1105,7 +1169,7 @@
         String expectedZoneId = result.getTimeZone().getID();
         // All our scenarios should return multiple matches. The only cases where this wouldn't be
         // true are places that use offsets like XX:15, XX:30 and XX:45.
-        assertFalse(result.getIsOnlyMatch());
+        assertFalse(result.isOnlyMatch());
         assertSameOffset(scenario.getActualTimeMillis(), expectedZoneId, scenario.getTimeZoneId());
         return expectedZoneId;
     }
@@ -1192,7 +1256,7 @@
             return this;
         }
 
-        Script verifyOnlyTimeWasSuggestedAndReset(PhoneTimeSuggestion timeSuggestion) {
+        Script verifyOnlyTimeWasSuggestedAndReset(TelephonyTimeSuggestion timeSuggestion) {
             verifyTimeZoneWasNotSet();
             verifyTimeWasSuggested(timeSuggestion);
             commitStateChanges();
@@ -1200,7 +1264,7 @@
         }
 
         Script verifyTimeSuggestedAndZoneSetAndReset(
-                PhoneTimeSuggestion timeSuggestion, String timeZoneId) {
+                TelephonyTimeSuggestion timeSuggestion, String timeZoneId) {
             verifyTimeZoneWasSet(timeZoneId);
             verifyTimeWasSuggested(timeSuggestion);
             commitStateChanges();
@@ -1220,9 +1284,9 @@
             mFakeTimeServiceHelper.deviceTimeZone.assertLatestEquals(timeZoneId);
         }
 
-        private void verifyTimeWasSuggested(PhoneTimeSuggestion phoneTimeSuggestion) {
+        private void verifyTimeWasSuggested(TelephonyTimeSuggestion timeSuggestion) {
             mFakeTimeServiceHelper.suggestedTime.assertChangeCount(1);
-            mFakeTimeServiceHelper.suggestedTime.assertLatestEquals(phoneTimeSuggestion);
+            mFakeTimeServiceHelper.suggestedTime.assertLatestEquals(timeSuggestion);
         }
 
         private void commitStateChanges() {
@@ -1288,7 +1352,7 @@
 
         // State we want to track.
         public TestState<String> deviceTimeZone = new TestState<>();
-        public TestState<PhoneTimeSuggestion> suggestedTime = new TestState<>();
+        public TestState<TelephonyTimeSuggestion> suggestedTime = new TestState<>();
 
         FakeTimeServiceHelper(FakeDeviceState fakeDeviceState) {
             mFakeDeviceState = fakeDeviceState;
@@ -1315,10 +1379,12 @@
         }
 
         @Override
-        public void suggestDeviceTime(PhoneTimeSuggestion phoneTimeSuggestion) {
-            suggestedTime.set(phoneTimeSuggestion);
-            // The fake time service just uses the latest suggestion.
-            mFakeDeviceState.currentTimeMillis = phoneTimeSuggestion.getUtcTime().getValue();
+        public void suggestDeviceTime(TelephonyTimeSuggestion timeSuggestion) {
+            suggestedTime.set(timeSuggestion);
+            if (timeSuggestion.getUtcTime() != null) {
+                // The fake time service just uses the latest suggestion.
+                mFakeDeviceState.currentTimeMillis = timeSuggestion.getUtcTime().getValue();
+            }
         }
 
         void commitState() {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java
index 6621c03..45af1c0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupport.java
@@ -18,11 +18,12 @@
 
 import static org.junit.Assert.fail;
 
-import android.app.timedetector.PhoneTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.icu.util.Calendar;
 import android.icu.util.GregorianCalendar;
 import android.icu.util.TimeZone;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
 
 import com.android.internal.telephony.NitzStateMachine.DeviceState;
 
@@ -270,11 +271,24 @@
         return cal.getTimeInMillis();
     }
 
-    public static PhoneTimeSuggestion createTimeSuggestionFromNitzSignal(
-            int phoneId, TimestampedValue<NitzData> nitzSignal) {
-        PhoneTimeSuggestion timeSuggestion =
-                new PhoneTimeSuggestion(phoneId, createTimeSignalFromNitzSignal(nitzSignal));
-        return timeSuggestion;
+    public static TelephonyTimeZoneSuggestion createEmptyTimeZoneSuggestion(int slotIndex) {
+        return new TelephonyTimeZoneSuggestion.Builder(slotIndex)
+                .addDebugInfo("Test")
+                .build();
+    }
+
+    public static TelephonyTimeSuggestion createEmptyTimeSuggestion(int slotIndex) {
+        return new TelephonyTimeSuggestion.Builder(slotIndex)
+                .addDebugInfo("Test")
+                .build();
+    }
+
+    public static TelephonyTimeSuggestion createTimeSuggestionFromNitzSignal(
+            int slotIndex, TimestampedValue<NitzData> nitzSignal) {
+        return new TelephonyTimeSuggestion.Builder(slotIndex)
+                .setUtcTime(createTimeSignalFromNitzSignal(nitzSignal))
+                .addDebugInfo("Test")
+                .build();
     }
 
     public static TimestampedValue<Long> createTimeSignalFromNitzSignal(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupportTest.java b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupportTest.java
index 4df0adf..dfeafee 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupportTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTestSupportTest.java
@@ -38,8 +38,9 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.timezone.CountryTimeZones.OffsetResult;
+
 import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
-import com.android.internal.telephony.TimeZoneLookupHelper.OffsetResult;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -115,7 +116,7 @@
                     NON_UNIQUE_US_ZONE_SCENARIO.getNetworkCountryIsoCode());
             List<String> possibleZones = Arrays.asList(NON_UNIQUE_US_ZONE_SCENARIO_ZONES);
             assertTrue(possibleZones.contains(actualLookupResult.getTimeZone().getID()));
-            assertFalse(actualLookupResult.getIsOnlyMatch());
+            assertFalse(actualLookupResult.isOnlyMatch());
         }
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
index a504dc1..53d80b2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
@@ -20,9 +20,9 @@
 import static org.junit.Assert.assertNotEquals;
 
 import android.os.Parcel;
-import android.telephony.ModemInfo;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.PhoneCapability;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.telephony.SimSlotCapability;
 
 import org.junit.Test;
 
@@ -31,53 +31,108 @@
 
 public class PhoneCapabilityTest {
     @Test
-    @SmallTest
-    public void basicTests() throws Exception {
-        int maxActiveVoiceCalls = 1;
-        int maxActiveData = 2;
-        int max5G = 3;
-        ModemInfo modemInfo = new ModemInfo(1, 2, true, false);
-        List<ModemInfo> logicalModemList = new ArrayList<>();
-        logicalModemList.add(modemInfo);
+    public void basicTests() {
+        int utranUeCategoryDl = 1;
+        int utranUeCategoryUl = 2;
+        int eutranUeCategoryDl = 3;
+        int eutranUeCategoryUl = 4;
+        long lingerTime = 5;
+        long supportedRats = 6;
+        List<Integer> geranBands = new ArrayList<>();
+        geranBands.add(1);
+        List<Integer> utranBands = new ArrayList<>();
+        utranBands.add(2);
+        List<Integer> eutranBands = new ArrayList<>();
+        eutranBands.add(3);
+        List<Integer> ngranBands = new ArrayList<>();
+        ngranBands.add(4);
+        List<String> logicalModemUuids = new ArrayList<>();
+        logicalModemUuids.add("com.google.android.lm0");
+        List<SimSlotCapability> simSlotCapabilities = new ArrayList<>();
+        simSlotCapabilities.add(new SimSlotCapability(1, 2));
+        List<List<Long>> concurrentFeaturesSupport = new ArrayList<>();
+        List<Long> feature = new ArrayList<>();
+        feature.add(PhoneCapability.MODEM_FEATURE_CDMA2000_EHRPD_REG);
+        concurrentFeaturesSupport.add(feature);
 
-        PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData, max5G,
-                logicalModemList, false);
+        PhoneCapability capability = new PhoneCapability(utranUeCategoryDl, utranUeCategoryUl,
+                eutranUeCategoryDl, eutranUeCategoryUl, lingerTime,
+                supportedRats, geranBands, utranBands, eutranBands, ngranBands, logicalModemUuids,
+                simSlotCapabilities, concurrentFeaturesSupport);
 
-        assertEquals(maxActiveVoiceCalls, capability.maxActiveVoiceCalls);
-        assertEquals(maxActiveData, capability.maxActiveData);
-        assertEquals(max5G, capability.max5G);
-        assertEquals(1, capability.logicalModemList.size());
-        assertEquals(modemInfo, capability.logicalModemList.get(0));
-        PhoneCapability toCompare = new PhoneCapability(
-                maxActiveVoiceCalls + 1, maxActiveData - 1, max5G, logicalModemList, false);
-        assertEquals(capability, new PhoneCapability(
-                maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList, false));
+        assertEquals(utranUeCategoryDl, capability.getUeCategory(false, AccessNetworkType.UTRAN));
+        assertEquals(utranUeCategoryUl, capability.getUeCategory(true, AccessNetworkType.UTRAN));
+        assertEquals(eutranUeCategoryDl, capability.getUeCategory(false, AccessNetworkType.EUTRAN));
+        assertEquals(eutranUeCategoryUl, capability.getUeCategory(true, AccessNetworkType.EUTRAN));
+        assertEquals(lingerTime, capability.getPsDataConnectionLingerTimeMillis());
+        assertEquals(supportedRats, capability.getSupportedRats());
+        assertEquals(geranBands, capability.getBands(AccessNetworkType.GERAN));
+        assertEquals(utranBands, capability.getBands(AccessNetworkType.UTRAN));
+        assertEquals(eutranBands, capability.getBands(AccessNetworkType.EUTRAN));
+        assertEquals(ngranBands, capability.getBands(AccessNetworkType.NGRAN));
+        assertEquals(logicalModemUuids, capability.getLogicalModemUuids());
+        assertEquals(simSlotCapabilities, capability.getSimSlotCapabilities());
+        assertEquals(concurrentFeaturesSupport, capability.getConcurrentFeaturesSupport());
+
+        PhoneCapability toCompare = new PhoneCapability(utranUeCategoryDl + 1,
+                utranUeCategoryUl + 1, eutranUeCategoryDl + 1, eutranUeCategoryUl + 1,
+                lingerTime + 1, supportedRats + 1, geranBands, utranBands, eutranBands, ngranBands,
+                logicalModemUuids, simSlotCapabilities, concurrentFeaturesSupport);
+        assertEquals(capability, new PhoneCapability(utranUeCategoryDl, utranUeCategoryUl,
+                eutranUeCategoryDl, eutranUeCategoryUl, lingerTime,
+                supportedRats, geranBands, utranBands, eutranBands, ngranBands, logicalModemUuids,
+                simSlotCapabilities, concurrentFeaturesSupport));
         assertNotEquals(capability, toCompare);
     }
 
     @Test
-    @SmallTest
-    public void parcelReadWrite() throws Exception {
-        int maxActiveVoiceCalls = 1;
-        int maxActiveData = 2;
-        int max5G = 3;
-        ModemInfo modemInfo = new ModemInfo(1, 2, true, false);
-        List<ModemInfo> logicalModemList = new ArrayList<>();
-        logicalModemList.add(modemInfo);
+    public void parcelReadWrite() {
+        int utranUeCategoryDl = 1;
+        int utranUeCategoryUl = 2;
+        int eutranUeCategoryDl = 3;
+        int eutranUeCategoryUl = 4;
+        long lingerTime = 5;
+        long supportedRats = 6;
+        List<Integer> geranBands = new ArrayList<>();
+        geranBands.add(1);
+        List<Integer> utranBands = new ArrayList<>();
+        utranBands.add(2);
+        List<Integer> eutranBands = new ArrayList<>();
+        eutranBands.add(3);
+        List<Integer> ngranBands = new ArrayList<>();
+        ngranBands.add(4);
+        List<String> logicalModemUuids = new ArrayList<>();
+        logicalModemUuids.add("com.google.android.lm0");
+        List<SimSlotCapability> simSlotCapabilities = new ArrayList<>();
+        simSlotCapabilities.add(new SimSlotCapability(1, 2));
+        List<List<Long>> concurrentFeaturesSupport = new ArrayList<>();
+        List<Long> feature = new ArrayList<>();
+        feature.add(PhoneCapability.MODEM_FEATURE_NETWORK_SCAN);
+        concurrentFeaturesSupport.add(feature);
 
-        PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData, max5G,
-                logicalModemList, false);
+        PhoneCapability capability = new PhoneCapability(utranUeCategoryDl, utranUeCategoryUl,
+                eutranUeCategoryDl, eutranUeCategoryUl, lingerTime,
+                supportedRats, geranBands, utranBands, eutranBands, ngranBands, logicalModemUuids,
+                simSlotCapabilities, concurrentFeaturesSupport);
 
         Parcel parcel = Parcel.obtain();
         capability.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
         PhoneCapability toCompare = PhoneCapability.CREATOR.createFromParcel(parcel);
 
-        assertEquals(maxActiveVoiceCalls, toCompare.maxActiveVoiceCalls);
-        assertEquals(maxActiveData, toCompare.maxActiveData);
-        assertEquals(max5G, toCompare.max5G);
-        assertEquals(1, toCompare.logicalModemList.size());
-        assertEquals(modemInfo, toCompare.logicalModemList.get(0));
+        assertEquals(utranUeCategoryDl, capability.getUeCategory(false, AccessNetworkType.UTRAN));
+        assertEquals(utranUeCategoryUl, capability.getUeCategory(true, AccessNetworkType.UTRAN));
+        assertEquals(eutranUeCategoryDl, capability.getUeCategory(false, AccessNetworkType.EUTRAN));
+        assertEquals(eutranUeCategoryUl, capability.getUeCategory(true, AccessNetworkType.EUTRAN));
+        assertEquals(lingerTime, capability.getPsDataConnectionLingerTimeMillis());
+        assertEquals(supportedRats, capability.getSupportedRats());
+        assertEquals(geranBands, capability.getBands(AccessNetworkType.GERAN));
+        assertEquals(utranBands, capability.getBands(AccessNetworkType.UTRAN));
+        assertEquals(eutranBands, capability.getBands(AccessNetworkType.EUTRAN));
+        assertEquals(ngranBands, capability.getBands(AccessNetworkType.NGRAN));
+        assertEquals(logicalModemUuids, capability.getLogicalModemUuids());
+        assertEquals(simSlotCapabilities, capability.getSimSlotCapabilities());
+        assertEquals(concurrentFeaturesSupport, capability.getConcurrentFeaturesSupport());
         assertEquals(capability, toCompare);
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
index 6f01a47..08e5a0a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
@@ -168,6 +168,7 @@
 
         // Verify set system property being called.
         verify(mMi).setMultiSimProperties(MODEM_COUNT_DUAL_MODEM);
+        verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(MODEM_COUNT_DUAL_MODEM));
 
         // Capture and verify registration notification.
         verify(mHandler).sendMessageAtTime(captor.capture(), anyLong());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerExecutorTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerExecutorTest.java
index 40940bd..73126f7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerExecutorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerExecutorTest.java
@@ -16,12 +16,10 @@
 package com.android.internal.telephony;
 
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.verify;
 
 import android.telephony.PhoneStateListener;
-import android.telephony.PhysicalChannelConfig;
 import android.telephony.ServiceState;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -30,8 +28,6 @@
 import org.junit.Test;
 
 import java.lang.reflect.Field;
-import java.util.Collections;
-import java.util.List;
 import java.util.concurrent.Executor;
 
 public class PhoneStateListenerExecutorTest extends TelephonyTest {
@@ -46,7 +42,6 @@
     private PhoneStateListener mPhoneStateListenerUT;
 
     private boolean mUserMobileDataState = false;
-    private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
 
     @Before
     public void setUp() throws Exception {
@@ -56,8 +51,8 @@
             @Override
             public void onServiceStateChanged(ServiceState serviceState) {
                 logd("Service State Changed");
-                mServiceState.setVoiceRegState(serviceState.getVoiceRegState());
-                mServiceState.setDataRegState(serviceState.getDataRegState());
+                mServiceState.setVoiceRegState(serviceState.getState());
+                mServiceState.setDataRegState(serviceState.getDataRegistrationState());
             }
 
             @Override
@@ -65,13 +60,6 @@
                 logd("User Mobile Data State Changed");
                 mUserMobileDataState = true;
             }
-
-            @Override
-            public void onPhysicalChannelConfigurationChanged(
-                    List<PhysicalChannelConfig> configs) {
-                logd("PhysicalChannelConfig Changed");
-                mPhysicalChannelConfigs = configs;
-            }
         };
     }
 
@@ -106,24 +94,4 @@
 
         assertTrue(mUserMobileDataState);
     }
-
-    @Test @SmallTest
-    public void testTriggerPhysicalChannelConfigurationChanged() throws Exception {
-        Field field = PhoneStateListener.class.getDeclaredField("callback");
-        field.setAccessible(true);
-
-        assertNull(mPhysicalChannelConfigs);
-
-        PhysicalChannelConfig config = new PhysicalChannelConfig.Builder()
-                .setCellConnectionStatus(PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING)
-                .setCellBandwidthDownlinkKhz(2000 /* bandwidth */)
-                .build();
-
-        List<PhysicalChannelConfig> configs = Collections.singletonList(config);
-
-        ((IPhoneStateListener) field.get(mPhoneStateListenerUT))
-            .onPhysicalChannelConfigurationChanged(configs);
-
-        assertTrue(mPhysicalChannelConfigs.equals(configs));
-    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
index 1198f4b..8c55442 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.Mockito.verify;
 
 import android.telephony.PhoneStateListener;
-import android.telephony.PhysicalChannelConfig;
 import android.telephony.ServiceState;
 import android.telephony.emergency.EmergencyNumber;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -35,8 +34,6 @@
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -44,7 +41,6 @@
 
     private PhoneStateListener mPhoneStateListenerUT;
     private boolean mUserMobileDataState = false;
-    private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
     private EmergencyNumber mCalledEmergencyNumber;
     private EmergencyNumber mTextedEmergencyNumber;
 
@@ -55,8 +51,8 @@
             @Override
             public void onServiceStateChanged(ServiceState serviceState) {
                 logd("Service State Changed");
-                mServiceState.setVoiceRegState(serviceState.getVoiceRegState());
-                mServiceState.setDataRegState(serviceState.getDataRegState());
+                mServiceState.setVoiceRegState(serviceState.getState());
+                mServiceState.setDataRegState(serviceState.getDataRegistrationState());
             }
 
             @Override
@@ -74,12 +70,6 @@
                 logd("OutgoingSmsEmergencyNumber Changed");
                 mTextedEmergencyNumber = emergencyNumber;
             }
-
-            @Override
-            public void onPhysicalChannelConfigurationChanged(List<PhysicalChannelConfig> configs) {
-                logd("PhysicalChannelConfig Changed");
-                mPhysicalChannelConfigs = configs;
-            }
         };
         processAllMessages();
     }
@@ -163,25 +153,4 @@
 
         assertTrue(mTextedEmergencyNumber.equals(emergencyNumber));
     }
-
-    @Test @SmallTest
-    public void testTriggerPhysicalChannelConfigurationChanged() throws Exception {
-        Field field = PhoneStateListener.class.getDeclaredField("callback");
-        field.setAccessible(true);
-
-        assertNull(mPhysicalChannelConfigs);
-
-        PhysicalChannelConfig config = new PhysicalChannelConfig.Builder()
-                .setCellConnectionStatus(PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING)
-                .setCellBandwidthDownlinkKhz(20000 /* bandwidth */)
-                .build();
-
-        List<PhysicalChannelConfig> configs = Collections.singletonList(config);
-
-        ((IPhoneStateListener) field.get(mPhoneStateListenerUT))
-            .onPhysicalChannelConfigurationChanged(configs);
-        processAllMessages();
-
-        assertTrue(mPhysicalChannelConfigs.equals(configs));
-    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java
index a69a9a6..a642818 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.anyString;
@@ -39,6 +40,8 @@
 import org.mockito.Mock;
 
 public class PhoneSubInfoControllerTest extends TelephonyTest {
+    private static final String FEATURE_ID = null;
+
     private PhoneSubInfoController mPhoneSubInfoControllerUT;
     private AppOpsManager mAppOsMgr;
 
@@ -54,8 +57,8 @@
         doReturn(1).when(mSubscriptionController).getPhoneId(eq(1));
         doReturn(2).when(mTelephonyManager).getPhoneCount();
         doReturn(2).when(mTelephonyManager).getActiveModemCount();
-        doReturn(true).when(mSubscriptionController).isActiveSubId(0, TAG);
-        doReturn(true).when(mSubscriptionController).isActiveSubId(1, TAG);
+        doReturn(true).when(mSubscriptionController).isActiveSubId(0, TAG, FEATURE_ID);
+        doReturn(true).when(mSubscriptionController).isActiveSubId(1, TAG, FEATURE_ID);
         doReturn(new int[]{0, 1}).when(mSubscriptionManager)
                 .getActiveSubscriptionIdList(anyBoolean());
 
@@ -66,8 +69,8 @@
 
         mAppOsMgr = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
 
-        mPhoneSubInfoControllerUT = new PhoneSubInfoController(mContext,
-                new Phone[]{mPhone, mSecondPhone});
+        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, mSecondPhone});
+        mPhoneSubInfoControllerUT = new PhoneSubInfoController(mContext);
 
         setupMocksForTelephonyPermissions();
         // TelephonyPermissions will query the READ_DEVICE_IDENTIFIERS op from AppOpManager to
@@ -89,8 +92,10 @@
         doReturn("353626073736741").when(mPhone).getDeviceId();
         doReturn("353626073736742").when(mSecondPhone).getDeviceId();
 
-        assertEquals("353626073736741", mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG));
-        assertEquals("353626073736742", mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG));
+        assertEquals("353626073736741",
+                mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG, FEATURE_ID));
+        assertEquals("353626073736742",
+                mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -105,7 +110,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG);
+            mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -113,7 +118,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG);
+            mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -125,7 +130,7 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG);
+            mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -133,7 +138,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG);
+            mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -146,7 +151,7 @@
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG);
+            mPhoneSubInfoControllerUT.getDeviceIdForPhone(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -154,7 +159,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG);
+            mPhoneSubInfoControllerUT.getDeviceIdForPhone(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -166,22 +171,27 @@
     @SmallTest
     public void testGetNai() {
         doReturn("aaa@example.com").when(mPhone).getNai();
-        assertEquals("aaa@example.com", mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG));
+        assertEquals("aaa@example.com",
+                mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("bbb@example.com").when(mSecondPhone).getNai();
-        assertEquals("bbb@example.com", mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG));
+        assertEquals("bbb@example.com",
+                mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
     @SmallTest
     public void testGetNaiWithOutPermission() {
+        // The READ_PRIVILEGED_PHONE_STATE permission, carrier privileges, or passing a device /
+        // profile owner access check is required to access subscriber identifiers. Since none of
+        // those are true for this test each case will result in a SecurityException being thrown.
         doReturn("aaa@example.com").when(mPhone).getNai();
         doReturn("bbb@example.com").when(mSecondPhone).getNai();
 
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -189,7 +199,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -200,25 +210,53 @@
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
-        assertNull(mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG));
+        try {
+            mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG, FEATURE_ID);
+            Assert.fail("expected Security Exception Thrown");
+        } catch (Exception ex) {
+            assertTrue(ex instanceof SecurityException);
+            assertTrue(ex.getMessage().contains("getNai"));
+        }
+
+        try {
+            mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG, FEATURE_ID);
+            Assert.fail("expected Security Exception Thrown");
+        } catch (Exception ex) {
+            assertTrue(ex instanceof SecurityException);
+            assertTrue(ex.getMessage().contains("getNai"));
+        }
 
         //case 3: no READ_PRIVILEGED_PHONE_STATE
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
-        assertEquals("aaa@example.com", mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG));
-        assertEquals("bbb@example.com", mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG));
+        try {
+            mPhoneSubInfoControllerUT.getNaiForSubscriber(0, TAG, FEATURE_ID);
+            Assert.fail("expected Security Exception Thrown");
+        } catch (Exception ex) {
+            assertTrue(ex instanceof SecurityException);
+            assertTrue(ex.getMessage().contains("getNai"));
+        }
+
+        try {
+            mPhoneSubInfoControllerUT.getNaiForSubscriber(1, TAG, FEATURE_ID);
+            Assert.fail("expected Security Exception Thrown");
+        } catch (Exception ex) {
+            assertTrue(ex instanceof SecurityException);
+            assertTrue(ex.getMessage().contains("getNai"));
+        }
     }
 
     @Test
     @SmallTest
     public void testGetImei() {
         doReturn("990000862471854").when(mPhone).getImei();
-        assertEquals("990000862471854", mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG));
+        assertEquals("990000862471854",
+                mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("990000862471855").when(mSecondPhone).getImei();
-        assertEquals("990000862471855", mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG));
+        assertEquals("990000862471855",
+                mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -233,7 +271,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -241,7 +279,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -253,7 +291,7 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -261,7 +299,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -273,7 +311,7 @@
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getImeiForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -281,7 +319,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getImeiForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -293,10 +331,10 @@
     @SmallTest
     public void testGetDeviceSvn() {
         doReturn("00").when(mPhone).getDeviceSvn();
-        assertEquals("00", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG));
+        assertEquals("00", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG, FEATURE_ID));
 
         doReturn("01").when(mSecondPhone).getDeviceSvn();
-        assertEquals("01", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG));
+        assertEquals("01", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -308,7 +346,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG);
+            mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -316,7 +354,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG);
+            mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -328,15 +366,15 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
 
-        assertNull(mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG, FEATURE_ID));
+        assertNull(mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG, FEATURE_ID));
 
         //case 3: no READ_PRIVILEGED_PHONE_STATE
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
-        assertEquals("00", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG));
-        assertEquals("01", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG));
+        assertEquals("00", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(0, TAG, FEATURE_ID));
+        assertEquals("01", mPhoneSubInfoControllerUT.getDeviceSvnUsingSubId(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -345,18 +383,18 @@
         //IMSI
         doReturn("310260426283121").when(mPhone).getSubscriberId();
         assertEquals("310260426283121", mPhoneSubInfoControllerUT
-                .getSubscriberIdForSubscriber(0, TAG));
+                .getSubscriberIdForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("310260426283122").when(mSecondPhone).getSubscriberId();
         assertEquals("310260426283122", mPhoneSubInfoControllerUT
-                .getSubscriberIdForSubscriber(1, TAG));
+                .getSubscriberIdForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
     @SmallTest
     public void testGetSubscriberIdWithInactiveSubId() {
         //IMSI
-        assertNull(mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(2, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(2, TAG, FEATURE_ID));
     }
 
     @Test
@@ -371,7 +409,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -379,7 +417,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -391,7 +429,7 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -399,7 +437,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -412,7 +450,7 @@
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -420,7 +458,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getSubscriberIdForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -434,11 +472,11 @@
         //IccId
         doReturn("8991101200003204510").when(mPhone).getIccSerialNumber();
         assertEquals("8991101200003204510", mPhoneSubInfoControllerUT
-                .getIccSerialNumberForSubscriber(0, TAG));
+                .getIccSerialNumberForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("8991101200003204511").when(mSecondPhone).getIccSerialNumber();
         assertEquals("8991101200003204511", mPhoneSubInfoControllerUT
-                .getIccSerialNumberForSubscriber(1, TAG));
+                .getIccSerialNumberForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -453,7 +491,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -461,7 +499,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -473,7 +511,7 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -481,7 +519,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -493,7 +531,7 @@
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -501,7 +539,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getIccSerialNumberForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -513,10 +551,12 @@
     @SmallTest
     public void testLine1Number() {
         doReturn("+18051234567").when(mPhone).getLine1Number();
-        assertEquals("+18051234567", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG));
+        assertEquals("+18051234567",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("+18052345678").when(mSecondPhone).getLine1Number();
-        assertEquals("+18052345678", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG));
+        assertEquals("+18052345678",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -535,14 +575,14 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         try {
-            mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
         }
 
         try {
-            mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -551,41 +591,49 @@
         /* case 2: only enable WRITE_SMS permission */
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_WRITE_SMS), anyInt(), eq(TAG));
-        assertEquals("+18051234567", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG));
-        assertEquals("+18052345678", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG));
+        assertEquals("+18051234567",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID));
+        assertEquals("+18052345678",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID));
 
         /* case 3: only enable READ_PRIVILEGED_PHONE_STATE */
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_WRITE_SMS), anyInt(), eq(TAG));
         mContextFixture.addCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE);
-        assertEquals("+18051234567", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG));
-        assertEquals("+18052345678", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG));
+        assertEquals("+18051234567",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID));
+        assertEquals("+18052345678",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID));
 
         /* case 4: only enable READ_PHONE_STATE permission */
         mContextFixture.removeCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE);
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
-        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID));
+        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID));
 
         /* case 5: enable appOsMgr READ_PHONE_PERMISSION & READ_PHONE_STATE */
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
-        assertEquals("+18051234567", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG));
-        assertEquals("+18052345678", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG));
+        assertEquals("+18051234567",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID));
+        assertEquals("+18052345678",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID));
 
         /* case 6: only enable READ_SMS */
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         mContextFixture.removeCallingOrSelfPermission(READ_PHONE_STATE);
         mContextFixture.addCallingOrSelfPermission(READ_SMS);
-        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID));
+        assertNull(mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID));
 
         /* case 7: enable READ_SMS and OP_READ_SMS */
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_SMS), anyInt(), eq(TAG));
-        assertEquals("+18051234567", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG));
-        assertEquals("+18052345678", mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG));
+        assertEquals("+18051234567",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(0, TAG, FEATURE_ID));
+        assertEquals("+18052345678",
+                mPhoneSubInfoControllerUT.getLine1NumberForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -593,11 +641,11 @@
     public void testLine1AlphaTag() {
         doReturn("LINE1_SIM_0").when(mPhone).getLine1AlphaTag();
         assertEquals("LINE1_SIM_0", mPhoneSubInfoControllerUT
-                .getLine1AlphaTagForSubscriber(0, TAG));
+                .getLine1AlphaTagForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("LINE1_SIM_1").when(mSecondPhone).getLine1AlphaTag();
         assertEquals("LINE1_SIM_1", mPhoneSubInfoControllerUT
-                .getLine1AlphaTagForSubscriber(1, TAG));
+                .getLine1AlphaTagForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -609,7 +657,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -617,7 +665,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -629,27 +677,29 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
 
-        assertNull(mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(1, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(0, TAG, FEATURE_ID));
+        assertNull(mPhoneSubInfoControllerUT.getLine1AlphaTagForSubscriber(1, TAG, FEATURE_ID));
 
         //case 3: no READ_PRIVILEGED_PHONE_STATE
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         assertEquals("LINE1_SIM_0", mPhoneSubInfoControllerUT
-                .getLine1AlphaTagForSubscriber(0, TAG));
+                .getLine1AlphaTagForSubscriber(0, TAG, FEATURE_ID));
         assertEquals("LINE1_SIM_1", mPhoneSubInfoControllerUT
-                .getLine1AlphaTagForSubscriber(1, TAG));
+                .getLine1AlphaTagForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
     @SmallTest
     public void testMsisdn() {
         doReturn("+18051234567").when(mPhone).getMsisdn();
-        assertEquals("+18051234567", mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG));
+        assertEquals("+18051234567",
+                mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("+18052345678").when(mSecondPhone).getMsisdn();
-        assertEquals("+18052345678", mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG));
+        assertEquals("+18052345678",
+                mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -661,7 +711,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -669,7 +719,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -681,15 +731,17 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
 
-        assertNull(mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG, FEATURE_ID));
+        assertNull(mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG, FEATURE_ID));
 
         //case 3: no READ_PRIVILEGED_PHONE_STATE
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
-        assertEquals("+18051234567", mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG));
-        assertEquals("+18052345678", mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG));
+        assertEquals("+18051234567",
+                mPhoneSubInfoControllerUT.getMsisdnForSubscriber(0, TAG, FEATURE_ID));
+        assertEquals("+18052345678",
+                mPhoneSubInfoControllerUT.getMsisdnForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -697,11 +749,11 @@
     public void testGetVoiceMailNumber() {
         doReturn("+18051234567").when(mPhone).getVoiceMailNumber();
         assertEquals("+18051234567", mPhoneSubInfoControllerUT
-                .getVoiceMailNumberForSubscriber(0, TAG));
+                .getVoiceMailNumberForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("+18052345678").when(mSecondPhone).getVoiceMailNumber();
         assertEquals("+18052345678", mPhoneSubInfoControllerUT
-                .getVoiceMailNumberForSubscriber(1, TAG));
+                .getVoiceMailNumberForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -713,7 +765,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -721,7 +773,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -733,17 +785,17 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
 
-        assertNull(mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(1, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(0, TAG, FEATURE_ID));
+        assertNull(mPhoneSubInfoControllerUT.getVoiceMailNumberForSubscriber(1, TAG, FEATURE_ID));
 
         //case 3: no READ_PRIVILEGED_PHONE_STATE
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         assertEquals("+18051234567", mPhoneSubInfoControllerUT
-                .getVoiceMailNumberForSubscriber(0, TAG));
+                .getVoiceMailNumberForSubscriber(0, TAG, FEATURE_ID));
         assertEquals("+18052345678", mPhoneSubInfoControllerUT
-                .getVoiceMailNumberForSubscriber(1, TAG));
+                .getVoiceMailNumberForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -751,11 +803,11 @@
     public void testGetVoiceMailAlphaTag() {
         doReturn("VM_SIM_0").when(mPhone).getVoiceMailAlphaTag();
         assertEquals("VM_SIM_0", mPhoneSubInfoControllerUT
-                .getVoiceMailAlphaTagForSubscriber(0, TAG));
+                .getVoiceMailAlphaTagForSubscriber(0, TAG, FEATURE_ID));
 
         doReturn("VM_SIM_1").when(mSecondPhone).getVoiceMailAlphaTag();
         assertEquals("VM_SIM_1", mPhoneSubInfoControllerUT
-                .getVoiceMailAlphaTagForSubscriber(1, TAG));
+                .getVoiceMailAlphaTagForSubscriber(1, TAG, FEATURE_ID));
     }
 
     @Test
@@ -767,7 +819,7 @@
         //case 1: no READ_PRIVILEGED_PHONE_STATE, READ_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION
         mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
         try {
-            mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(0, TAG);
+            mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(0, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -775,7 +827,7 @@
         }
 
         try {
-            mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(1, TAG);
+            mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(1, TAG, FEATURE_ID);
             Assert.fail("expected Security Exception Thrown");
         } catch (Exception ex) {
             assertTrue(ex instanceof SecurityException);
@@ -787,16 +839,16 @@
         doReturn(AppOpsManager.MODE_ERRORED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
 
-        assertNull(mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(0, TAG));
-        assertNull(mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(1, TAG));
+        assertNull(mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(0, TAG, FEATURE_ID));
+        assertNull(mPhoneSubInfoControllerUT.getVoiceMailAlphaTagForSubscriber(1, TAG, FEATURE_ID));
 
         //case 3: no READ_PRIVILEGED_PHONE_STATE
         mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE);
         doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp(
                 eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG));
         assertEquals("VM_SIM_0", mPhoneSubInfoControllerUT
-                .getVoiceMailAlphaTagForSubscriber(0, TAG));
+                .getVoiceMailAlphaTagForSubscriber(0, TAG, FEATURE_ID));
         assertEquals("VM_SIM_1", mPhoneSubInfoControllerUT
-                .getVoiceMailAlphaTagForSubscriber(1, TAG));
+                .getVoiceMailAlphaTagForSubscriber(1, TAG, FEATURE_ID));
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index fe0e74f..f0056d9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -17,12 +17,14 @@
 package com.android.internal.telephony;
 
 import static android.telephony.CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG;
+import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION;
 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS;
 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED;
 
 import static com.android.internal.telephony.PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS;
 import static com.android.internal.telephony.PhoneSwitcher.EVENT_DATA_ENABLED_CHANGED;
+import static com.android.internal.telephony.PhoneSwitcher.EVENT_MULTI_SIM_CONFIG_CHANGED;
 import static com.android.internal.telephony.PhoneSwitcher.EVENT_PRECISE_CALL_STATE_CHANGED;
 
 import static org.junit.Assert.assertEquals;
@@ -45,8 +47,9 @@
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
+import android.net.NetworkProvider;
 import android.net.NetworkRequest;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
@@ -58,6 +61,8 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.internal.telephony.dataconnection.DataEnabledSettings;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -81,16 +86,14 @@
     private static final int ACTIVE_PHONE_SWITCH = 1;
 
     @Mock
-    private ITelephonyRegistry.Stub mTelRegistryMock;
-    @Mock
-    private ITelephonyRegistry mTelRegistryInterfaceMock;
-    @Mock
     private CommandsInterface mCommandsInterface0;
     @Mock
     private CommandsInterface mCommandsInterface1;
     @Mock
     private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest.
     @Mock
+    private DataEnabledSettings mDataEnabledSettings2;
+    @Mock
     private Handler mActivePhoneSwitchHandler;
     @Mock
     private GsmCdmaCall mActiveCall;
@@ -106,27 +109,30 @@
     CompletableFuture<Boolean> mFuturePhone;
 
     private PhoneSwitcher mPhoneSwitcher;
-    private IOnSubscriptionsChangedListener mSubChangedListener;
+    private SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener;
     private ConnectivityManager mConnectivityManager;
     // The messenger of PhoneSwitcher used to receive network requests.
-    private Messenger mNetworkFactoryMessenger = null;
+    private Messenger mNetworkProviderMessenger = null;
     private int mDefaultDataSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-    private CommandsInterface[] mCommandsInterfaces;
     private int[][] mSlotIndexToSubId;
     private boolean[] mDataAllowed;
+    private int mActiveModemCount = 2;
+    private int mSupportedModemCount = 2;
+    private int mMaxDataAttachModemCount = 1;
 
     @Before
     public void setUp() throws Exception {
         super.setUp(getClass().getSimpleName());
-
-        PhoneCapability phoneCapability = new PhoneCapability(1, 1, 0, null, false);
+        PhoneCapability phoneCapability = new PhoneCapability(0, 0, 0, 0, 0, 0,
+                null, null, null, null, null, null, null);
         doReturn(phoneCapability).when(mPhoneConfigurationManager).getCurrentPhoneCapability();
-        mServiceManagerMockedServices.put("telephony.registry", mTelRegistryMock);
-        doReturn(mTelRegistryInterfaceMock).when(mTelRegistryMock).queryLocalInterface(any());
 
         doReturn(Call.State.ACTIVE).when(mActiveCall).getState();
         doReturn(Call.State.IDLE).when(mInactiveCall).getState();
         doReturn(Call.State.HOLDING).when(mHoldingCall).getState();
+
+        replaceInstance(Phone.class, "mCi", mPhone, mCommandsInterface0);
+        replaceInstance(Phone.class, "mCi", mPhone2, mCommandsInterface1);
     }
 
     @After
@@ -140,9 +146,7 @@
     @Test
     @SmallTest
     public void testRegister() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
-        initialize(numPhones, maxActivePhones);
+        initialize();
 
         // verify nothing has been done while there are no inputs
         assertFalse("data allowed initially", mDataAllowed[0]);
@@ -314,9 +318,7 @@
     @Test
     @SmallTest
     public void testPrioritization() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
-        initialize(numPhones, maxActivePhones);
+        initialize();
 
         addInternetNetworkRequest(null, 50);
         setSlotIndexToSubId(0, 0);
@@ -341,15 +343,13 @@
     }
 
     /**
-     * Verify we don't send spurious DATA_ALLOWED calls when another NetworkFactory
+     * Verify we don't send spurious DATA_ALLOWED calls when another NetworkProvider
      * wins (ie, switch to wifi).
      */
     @Test
     @SmallTest
     public void testHigherPriorityDefault() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
-        initialize(numPhones, maxActivePhones);
+        initialize();
 
         addInternetNetworkRequest(null, 50);
 
@@ -383,9 +383,7 @@
     @Test
     @SmallTest
     public void testSetPreferredData() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
-        initialize(numPhones, maxActivePhones);
+        initialize();
 
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
@@ -416,10 +414,8 @@
     @Test
     @SmallTest
     public void testSetPreferredDataModemCommand() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         mPhoneSwitcher.registerForActivePhoneSwitch(mActivePhoneSwitchHandler,
                 ACTIVE_PHONE_SWITCH, null);
         mPhoneSwitcher.registerForActivePhoneSwitch(mActivePhoneSwitchHandler,
@@ -484,10 +480,8 @@
     @Test
     @SmallTest
     public void testSetPreferredDataWithValidation() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
 
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
@@ -535,10 +529,8 @@
     @Test
     @SmallTest
     public void testNonDefaultDataPhoneInCall() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
@@ -584,10 +576,8 @@
     @Test
     @SmallTest
     public void testNetworkRequestOnNonDefaultData() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
@@ -607,14 +597,12 @@
     @Test
     @SmallTest
     public void testEmergencyOverrideSuccessBeforeCallStarts() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
-        setMsimDefaultDataSubId(numPhones, 1);
+        setMsimDefaultDataSubId(1);
         clearInvocations(mMockRadioConfig);
 
         // override the phone ID in prep for emergency call
@@ -623,20 +611,18 @@
         processAllMessages();
         verify(mFuturePhone).complete(true);
         // Make sure the correct broadcast is sent out for the overridden phone ID
-        verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(2));
+        verify(mTelephonyRegistryManager).notifyActiveDataSubIdChanged(eq(2));
     }
 
     @Test
     @SmallTest
     public void testEmergencyOverrideNoDdsChange() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
-        setMsimDefaultDataSubId(numPhones, 1);
+        setMsimDefaultDataSubId(1);
         clearInvocations(mMockRadioConfig);
 
         // override the phone ID in prep for emergency call
@@ -652,17 +638,15 @@
     @SmallTest
     public void testEmergencyOverrideEndSuccess() throws Exception {
         PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 500;
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
-        setMsimDefaultDataSubId(numPhones, 1);
+        setMsimDefaultDataSubId(1);
         setAllPhonesInactive();
         clearInvocations(mMockRadioConfig);
-        clearInvocations(mTelRegistryInterfaceMock);
+        clearInvocations(mTelephonyRegistryManager);
 
         // override the phone ID in prep for emergency call
         mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, mFuturePhone);
@@ -674,30 +658,28 @@
         notifyPhoneAsInCall(mPhone2);
         notifyPhoneAsInactive(mPhone2);
 
-        clearInvocations(mTelRegistryInterfaceMock);
+        clearInvocations(mTelephonyRegistryManager);
         // Verify that the DDS is successfully switched back after 1 second + base ECBM timeout
         moveTimeForward(ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS + 1000);
         processAllMessages();
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         // Make sure the correct broadcast is sent out for the phone ID
-        verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+        verify(mTelephonyRegistryManager).notifyActiveDataSubIdChanged(eq(1));
     }
 
     @Test
     @SmallTest
     public void testEmergencyOverrideEcbmStartEnd() throws Exception {
         PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 500;
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
-        setMsimDefaultDataSubId(numPhones, 1);
+        setMsimDefaultDataSubId(1);
         setAllPhonesInactive();
         clearInvocations(mMockRadioConfig);
-        clearInvocations(mTelRegistryInterfaceMock);
+        clearInvocations(mTelephonyRegistryManager);
 
         // override the phone ID in prep for emergency call
         mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, mFuturePhone);
@@ -718,10 +700,10 @@
         processAllMessages();
         verify(mMockRadioConfig, never()).setPreferredDataModem(eq(0), any());
         // Make sure the correct broadcast is sent out for the phone ID
-        verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(2));
+        verify(mTelephonyRegistryManager).notifyActiveDataSubIdChanged(eq(2));
 
         // End ECBM
-        clearInvocations(mTelRegistryInterfaceMock);
+        clearInvocations(mTelephonyRegistryManager);
         ecbmMessage = getEcbmRegistration(mPhone2);
         notifyEcbmEnd(mPhone2, ecbmMessage);
         // Verify that the DDS is successfully switched back after 1 second.
@@ -729,24 +711,22 @@
         processAllMessages();
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         // Make sure the correct broadcast is sent out for the phone ID
-        verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+        verify(mTelephonyRegistryManager).notifyActiveDataSubIdChanged(eq(1));
     }
 
     @Test
     @SmallTest
     public void testEmergencyOverrideNoCallStart() throws Exception {
         PhoneSwitcher.DEFAULT_DATA_OVERRIDE_TIMEOUT_MS = 500;
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
-        setMsimDefaultDataSubId(numPhones, 1);
+        setMsimDefaultDataSubId(1);
         setAllPhonesInactive();
         clearInvocations(mMockRadioConfig);
-        clearInvocations(mTelRegistryInterfaceMock);
+        clearInvocations(mTelephonyRegistryManager);
 
         // override the phone ID in prep for emergency call
         mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, mFuturePhone);
@@ -759,24 +739,22 @@
         processAllMessages();
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         // Make sure the correct broadcast is sent out for the phone ID
-        verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+        verify(mTelephonyRegistryManager).notifyActiveDataSubIdChanged(eq(1));
     }
 
     @Test
     @SmallTest
     public void testEmergencyOverrideMultipleOverrideRequests() throws Exception {
         PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 500;
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
         // Phone 0 has sub 1, phone 1 has sub 2.
         // Sub 1 is default data sub.
         // Both are active subscriptions are active sub, as they are in both active slots.
-        setMsimDefaultDataSubId(numPhones, 1);
+        setMsimDefaultDataSubId(1);
         setAllPhonesInactive();
         clearInvocations(mMockRadioConfig);
-        clearInvocations(mTelRegistryInterfaceMock);
+        clearInvocations(mTelephonyRegistryManager);
 
         // override the phone ID in prep for emergency call
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
@@ -808,16 +786,14 @@
         processAllMessages();
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         // Make sure the correct broadcast is sent out for the phone ID
-        verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+        verify(mTelephonyRegistryManager).notifyActiveDataSubIdChanged(eq(1));
     }
 
     @Test
     @SmallTest
     public void testSetPreferredDataCallback() throws Exception {
-        final int numPhones = 2;
-        final int maxActivePhones = 1;
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
-        initialize(numPhones, maxActivePhones);
+        initialize();
 
         // Mark sub 2 as opportunistic.
         doReturn(true).when(mSubscriptionController).isOpportunistic(2);
@@ -910,6 +886,36 @@
         verify(mSetOpptDataCallback2).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS);
     }
 
+
+    @Test
+    @SmallTest
+    public void testMultiSimConfigChange() throws Exception {
+        doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+        mActiveModemCount = 1;
+        initialize();
+        sendPreferredDataSuccessResult(0);
+
+        // Phone 0 has sub 1, phone 1 has sub 2.
+        // Sub 1 is default data sub.
+        // Both are active subscriptions are active sub, as they are in both active slots.
+        setSlotIndexToSubId(0, 1);
+        setDefaultDataSubId(1);
+
+        setNumPhones(MODEM_COUNT_DUAL_MODEM, MODEM_COUNT_DUAL_MODEM);
+        AsyncResult result = new AsyncResult(null, MODEM_COUNT_DUAL_MODEM, null);
+        Message.obtain(mPhoneSwitcher, EVENT_MULTI_SIM_CONFIG_CHANGED, result).sendToTarget();
+        processAllMessages();
+
+        verify(mPhone2).registerForEmergencyCallToggle(any(), anyInt(), any());
+        verify(mPhone2).registerForPreciseCallStateChanged(any(), anyInt(), any());
+        verify(mDataEnabledSettings2).registerForDataEnabledChanged(any(), anyInt(), any());
+
+        clearInvocations(mMockRadioConfig);
+        setSlotIndexToSubId(1, 2);
+        setDefaultDataSubId(2);
+        verify(mMockRadioConfig).setPreferredDataModem(eq(1), any());
+    }
+
     /* Private utility methods start here */
 
     private void setAllPhonesInactive() {
@@ -941,6 +947,7 @@
 
     private void notifyDataEnabled(boolean dataEnabled) {
         doReturn(dataEnabled).when(mDataEnabledSettings).isDataEnabled(anyInt());
+        doReturn(dataEnabled).when(mDataEnabledSettings2).isDataEnabled(anyInt());
         mPhoneSwitcher.sendEmptyMessage(EVENT_DATA_ENABLED_CHANGED);
         processAllMessages();
     }
@@ -982,13 +989,13 @@
         processAllMessages();
     }
 
-    private void setMsimDefaultDataSubId(int numPhones, int defaultDataSub) throws Exception {
-        for (int i = 0; i < numPhones; i++) {
+    private void setMsimDefaultDataSubId(int defaultDataSub) throws Exception {
+        for (int i = 0; i < mActiveModemCount; i++) {
             setSlotIndexToSubId(i, i + 1);
         }
         setDefaultDataSubId(defaultDataSub);
         NetworkRequest internetRequest = addInternetNetworkRequest(null, 50);
-        for (int i = 0; i < numPhones; i++) {
+        for (int i = 0; i < mActiveModemCount; i++) {
             if (defaultDataSub == (i + 1)) {
                 // sub id is always phoneId+1 for testing
                 assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, i));
@@ -1004,54 +1011,52 @@
         processAllMessages();
     }
 
-    private void initialize(int numPhones, int maxActivePhones) throws Exception {
+    private void initialize() throws Exception {
         mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
                 sNetworkAttributes);
 
-        setNumPhones(numPhones);
+        setNumPhones(mActiveModemCount, mSupportedModemCount);
 
         initializeSubControllerMock();
-        initializeCommandInterfacesMock(numPhones);
+        initializeCommandInterfacesMock();
         initializeTelRegistryMock();
         initializeConnManagerMock();
 
-        mPhoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones,
-                mContext, mSubscriptionController, Looper.myLooper(),
-                mTelRegistryMock, mCommandsInterfaces, mPhones);
+        mPhoneSwitcher = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper());
         processAllMessages();
 
-        verify(mTelRegistryMock).addOnSubscriptionsChangedListener(
-                eq(mContext.getOpPackageName()), any());
+        verify(mTelephonyRegistryManager).addOnSubscriptionsChangedListener(any(), any());
     }
 
     /**
      * Certain variables needs initialized depending on number of phones.
      */
-    private void setNumPhones(int numPhones) {
-        mDataAllowed = new boolean[numPhones];
-        mSlotIndexToSubId = new int[numPhones][];
+    private void setNumPhones(int activeModemCount, int supportedModemCount) throws Exception {
+        mDataAllowed = new boolean[supportedModemCount];
+        mSlotIndexToSubId = new int[supportedModemCount][];
         doReturn(0).when(mPhone).getPhoneId();
         doReturn(1).when(mPhone2).getPhoneId();
         doReturn(true).when(mPhone2).isUserDataEnabled();
-        doReturn(mDataEnabledSettings).when(mPhone2).getDataEnabledSettings();
-        for (int i = 0; i < numPhones; i++) {
+        doReturn(mDataEnabledSettings2).when(mPhone2).getDataEnabledSettings();
+        for (int i = 0; i < supportedModemCount; i++) {
             mSlotIndexToSubId[i] = new int[1];
             mSlotIndexToSubId[i][0] = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
 
-        doReturn(numPhones).when(mTelephonyManager).getPhoneCount();
-        doReturn(numPhones).when(mTelephonyManager).getActiveModemCount();
-        if (numPhones == 1) {
-            mCommandsInterfaces = new CommandsInterface[] {mCommandsInterface0};
-            mPhones = new Phone[] {mPhone};
-        } else if (numPhones == 2) {
-            mCommandsInterfaces =
-                    new CommandsInterface[] {mCommandsInterface0, mCommandsInterface1};
-            mPhones = new Phone[] {mPhone, mPhone2};
+        doReturn(activeModemCount).when(mTelephonyManager).getPhoneCount();
+        doReturn(activeModemCount).when(mTelephonyManager).getActiveModemCount();
+        doReturn(supportedModemCount).when(mTelephonyManager).getSupportedModemCount();
+
+        if (activeModemCount == 1) {
+            mPhones = new Phone[]{mPhone};
+        } else if (activeModemCount == 2) {
+            mPhones = new Phone[]{mPhone, mPhone2};
         }
+
+        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
     }
 
-    private void initializeCommandInterfacesMock(int numPhones) {
+    private void initializeCommandInterfacesMock() {
         // Tell PhoneSwitcher that radio is on.
         doAnswer(invocation -> {
             Handler handler = (Handler) invocation.getArguments()[0];
@@ -1067,7 +1072,7 @@
             return null;
         }).when(mCommandsInterface0).setDataAllowed(anyBoolean(), any());
 
-        if (numPhones == 2) {
+        if (mSupportedModemCount > 1) {
             doAnswer(invocation -> {
                 mDataAllowed[1] = (boolean) invocation.getArguments()[0];
                 return null;
@@ -1081,16 +1086,16 @@
      */
     private void initializeTelRegistryMock() throws Exception {
         doAnswer(invocation -> {
-            IOnSubscriptionsChangedListener subChangedListener =
-                    (IOnSubscriptionsChangedListener) invocation.getArguments()[1];
+            SubscriptionManager.OnSubscriptionsChangedListener subChangedListener =
+                    (SubscriptionManager.OnSubscriptionsChangedListener) invocation.getArguments()[0];
             mSubChangedListener = subChangedListener;
             mSubChangedListener.onSubscriptionsChanged();
             return null;
-        }).when(mTelRegistryMock).addOnSubscriptionsChangedListener(any(), any());
+        }).when(mTelephonyRegistryManager).addOnSubscriptionsChangedListener(any(), any());
     }
 
     /**
-     * Capture mNetworkFactoryMessenger so that testing can request or release
+     * Capture mNetworkProviderMessenger so that testing can request or release
      * network requests on PhoneSwitcher.
      */
     private void initializeConnManagerMock() {
@@ -1098,13 +1103,14 @@
                 mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
 
         doAnswer(invocation -> {
-            mNetworkFactoryMessenger = invocation.getArgument(0);
+            mNetworkProviderMessenger =
+                    ((NetworkProvider) invocation.getArgument(0)).getMessenger();
             return null;
-        }).when(mConnectivityManager).registerNetworkFactory(any(), any());
+        }).when(mConnectivityManager).registerNetworkProvider(any());
     }
 
     /**
-     * Capture mNetworkFactoryMessenger so that testing can request or release
+     * Capture mNetworkProviderMessenger so that testing can request or release
      * network requests on PhoneSwitcher.
      */
     private void initializeSubControllerMock() {
@@ -1159,16 +1165,17 @@
         }
 
         if (subId != null) {
-            netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
+            netCap.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                    .setSubscriptionId(subId).build());
         }
         NetworkRequest networkRequest = new NetworkRequest(netCap, ConnectivityManager.TYPE_NONE,
                 0, NetworkRequest.Type.REQUEST);
 
         Message message = Message.obtain();
-        message.what = android.net.NetworkFactory.CMD_REQUEST_NETWORK;
+        message.what = android.net.NetworkProvider.CMD_REQUEST_NETWORK;
         message.arg1 = score;
         message.obj = networkRequest;
-        mNetworkFactoryMessenger.send(message);
+        mNetworkProviderMessenger.send(message);
         processAllMessages();
 
         return networkRequest;
@@ -1182,18 +1189,18 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
         if (subId != null) {
-            netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
+            netCap.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                    .setSubscriptionId(subId).build());
         }
         NetworkRequest networkRequest = new NetworkRequest(netCap, ConnectivityManager.TYPE_NONE,
                 1, NetworkRequest.Type.REQUEST);
 
         Message message = Message.obtain();
-        message.what = android.net.NetworkFactory.CMD_REQUEST_NETWORK;
+        message.what = android.net.NetworkProvider.CMD_REQUEST_NETWORK;
         message.arg1 = 50; // Score
         message.obj = networkRequest;
-        mNetworkFactoryMessenger.send(message);
+        mNetworkProviderMessenger.send(message);
         processAllMessages();
 
         return networkRequest;
@@ -1204,9 +1211,9 @@
      */
     private void releaseNetworkRequest(NetworkRequest networkRequest) throws Exception {
         Message message = Message.obtain();
-        message.what = android.net.NetworkFactory.CMD_CANCEL_REQUEST;
+        message.what = android.net.NetworkProvider.CMD_CANCEL_REQUEST;
         message.obj = networkRequest;
-        mNetworkFactoryMessenger.send(message);
+        mNetworkProviderMessenger.send(message);
         processAllMessages();
     }
-}
\ No newline at end of file
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java
new file mode 100644
index 0000000..128e6d8
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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 com.android.internal.telephony.ProxyController.EVENT_MULTI_SIM_CONFIG_CHANGED;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ProxyControllerTest extends TelephonyTest {
+    @Mock
+    Phone mPhone2;
+
+    ProxyController mProxyController;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp(getClass().getSimpleName());
+        replaceInstance(ProxyController.class, "sProxyController", null, null);
+        mProxyController = ProxyController.getInstance(mContext);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Restore system properties.
+        super.tearDown();
+    }
+
+    @Test
+    @SmallTest
+    public void testMultiSimConfigChange() throws Exception {
+        ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+        ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(int.class);
+
+        // Switch to dual-SIM and send multi sim config change callback.
+        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mPhone2});
+        Message.obtain(mProxyController.mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED).sendToTarget();
+        processAllMessages();
+        verify(mPhone2).registerForRadioCapabilityChanged(any(), anyInt(), any());
+
+        // Switch to single-SIM and verify there's at least no crash.
+        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
+        Message.obtain(mProxyController.mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED).sendToTarget();
+        processAllMessages();
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index 3874261..24c9351 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,17 +102,17 @@
 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.InetAddresses;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
 import android.os.Handler;
 import android.os.IPowerManager;
 import android.os.Looper;
@@ -119,12 +124,14 @@
 import android.telephony.CellIdentityCdma;
 import android.telephony.CellIdentityGsm;
 import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityNr;
 import android.telephony.CellIdentityTdscdma;
 import android.telephony.CellIdentityWcdma;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoCdma;
 import android.telephony.CellInfoGsm;
 import android.telephony.CellInfoLte;
+import android.telephony.CellInfoNr;
 import android.telephony.CellInfoTdscdma;
 import android.telephony.CellInfoWcdma;
 import android.telephony.CellSignalStrengthCdma;
@@ -156,6 +163,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 @RunWith(AndroidTestingRunner.class)
@@ -171,11 +179,18 @@
     @Mock
     private ConnectivityManager mConnectionManager;
     @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
     private IRadio mRadioProxy;
     @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;
@@ -205,6 +220,7 @@
     private static final int MNC = 260;
     private static final String MNC_STR = "260";
     private static final int NETWORK_ID = 65534;
+    private static final int NRARFCN = 3279165;
     private static final int PCI = 503;
     private static final int PSC = 500;
     private static final int RIL_TIMESTAMP_TYPE_OEM_RIL = 3;
@@ -258,6 +274,9 @@
             .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
         doReturn(mConnectionManager).when(context)
             .getSystemService(Context.CONNECTIVITY_SERVICE);
+        doReturn(mTelephonyManager).when(context)
+                .getSystemService(Context.TELEPHONY_SERVICE);
+        doReturn(true).when(mTelephonyManager).isDataCapable();
         PowerManager powerManager = new PowerManager(context, mock(IPowerManager.class),
                 new Handler(Looper.myLooper()));
         doReturn(powerManager).when(context).getSystemService(Context.POWER_SERVICE);
@@ -270,7 +289,7 @@
         doReturn(mOemHookProxy).when(mRILUnderTest).getOemHookProxy(any());
 
         try {
-            replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersion);
+            replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV10);
         } catch (Exception e) {
         }
     }
@@ -1152,7 +1171,7 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityLte cil = new CellIdentityLte(CI, PCI, TAC, EARFCN, Integer.MAX_VALUE, MCC_STR,
-                MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
+                MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, Collections.emptyList(), null);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
                 RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE);
         expected.setCellIdentity(cil);
@@ -1193,7 +1212,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityGsm ci = new CellIdentityGsm(
-                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
+                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT,
+                Collections.emptyList());
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
                 RSSI, BIT_ERROR_RATE, TIMING_ADVANCE);
         expected.setCellIdentity(ci);
@@ -1233,7 +1253,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityWcdma ci = new CellIdentityWcdma(
-                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
+                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma(
                 RSSI, BIT_ERROR_RATE, Integer.MAX_VALUE, Integer.MAX_VALUE);
         expected.setCellIdentity(ci);
@@ -1275,7 +1296,8 @@
         expected.setTimeStamp(TIMESTAMP);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
         CellIdentityTdscdma ci = new CellIdentityTdscdma(
-                MCC_STR, MNC_STR, LAC, CID, PSC, UARFCN, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
+                MCC_STR, MNC_STR, LAC, CID, PSC, UARFCN, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellSignalStrengthTdscdma cs = new CellSignalStrengthTdscdma(
                 RSSI, BIT_ERROR_RATE, RSCP);
         expected.setCellIdentity(ci);
@@ -1337,7 +1359,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityLte cil = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
                 RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE);
         expected.setCellIdentity(cil);
@@ -1358,7 +1381,7 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityLte cil = new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR,
-                EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
+                EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, Collections.emptyList(), null);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
                 RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE);
         expected.setCellIdentity(cil);
@@ -1381,7 +1404,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityLte cil = new CellIdentityLte(
-                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
+                CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
                 RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE);
         expected.setCellIdentity(cil);
@@ -1401,7 +1425,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityGsm ci = new CellIdentityGsm(
-                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
                 RSSI, BIT_ERROR_RATE, TIMING_ADVANCE);
         expected.setCellIdentity(ci);
@@ -1422,7 +1447,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityGsm ci = new CellIdentityGsm(
-                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
+                LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT,
+                Collections.emptyList());
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
                 RSSI, BIT_ERROR_RATE, TIMING_ADVANCE);
         expected.setCellIdentity(ci);
@@ -1445,7 +1471,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityGsm ci = new CellIdentityGsm(
-                LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
                 RSSI, BIT_ERROR_RATE, TIMING_ADVANCE);
         expected.setCellIdentity(ci);
@@ -1466,7 +1493,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityWcdma ci = new CellIdentityWcdma(
-                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellSignalStrengthWcdma cs =
                 new CellSignalStrengthWcdma(RSSI, BIT_ERROR_RATE, RSCP, ECNO);
         expected.setCellIdentity(ci);
@@ -1487,7 +1515,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityWcdma ci = new CellIdentityWcdma(
-                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
+                LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma(
                 RSSI, BIT_ERROR_RATE, RSCP, ECNO);
         expected.setCellIdentity(ci);
@@ -1510,7 +1539,8 @@
         expected.setRegistered(false);
         expected.setTimeStamp(TIMESTAMP);
         CellIdentityWcdma ci = new CellIdentityWcdma(
-                LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
+                LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList(), null);
         CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma(
                 RSSI, BIT_ERROR_RATE, RSCP, ECNO);
         expected.setCellIdentity(ci);
@@ -1563,6 +1593,48 @@
     }
 
     @Test
+    public void testConvertHalCellInfoList_1_4ForNr() {
+        android.hardware.radio.V1_4.CellInfoNr cellinfo =
+                new android.hardware.radio.V1_4.CellInfoNr();
+        cellinfo.cellidentity.nci = CI;
+        cellinfo.cellidentity.pci = PCI;
+        cellinfo.cellidentity.tac = TAC;
+        cellinfo.cellidentity.nrarfcn = NRARFCN;
+        cellinfo.cellidentity.mcc = MCC_STR;
+        cellinfo.cellidentity.mnc = MNC_STR;
+        cellinfo.cellidentity.operatorNames.alphaLong = ALPHA_LONG;
+        cellinfo.cellidentity.operatorNames.alphaShort = ALPHA_SHORT;
+        cellinfo.signalStrength.ssRsrp = RSRP;
+        cellinfo.signalStrength.ssRsrq = RSRQ;
+        cellinfo.signalStrength.ssSinr = SIGNAL_NOISE_RATIO;
+        cellinfo.signalStrength.csiRsrp = RSRP;
+        cellinfo.signalStrength.csiRsrq = RSRQ;
+        cellinfo.signalStrength.csiSinr = SIGNAL_NOISE_RATIO;
+
+        android.hardware.radio.V1_4.CellInfo record = new android.hardware.radio.V1_4.CellInfo();
+        record.info.nr(cellinfo);
+
+        ArrayList<android.hardware.radio.V1_4.CellInfo> records = new ArrayList<>();
+        records.add(record);
+
+        ArrayList<CellInfo> ret = RIL.convertHalCellInfoList_1_4(records);
+
+        CellInfoNr cellInfoNr = (CellInfoNr) ret.get(0);
+        CellIdentityNr cellIdentityNr = (CellIdentityNr) cellInfoNr.getCellIdentity();
+        CellSignalStrengthNr signalStrengthNr =
+                (CellSignalStrengthNr) cellInfoNr.getCellSignalStrength();
+
+        CellIdentityNr expectedCellIdentity = new CellIdentityNr(PCI, TAC, NRARFCN,
+                Collections.emptyList(), MCC_STR, MNC_STR, CI, ALPHA_LONG, ALPHA_SHORT,
+                Collections.emptyList());
+        CellSignalStrengthNr expectedSignalStrength = new CellSignalStrengthNr(-RSRP, -RSRQ,
+                SIGNAL_NOISE_RATIO, -RSRP, -RSRQ, SIGNAL_NOISE_RATIO);
+
+        assertEquals(expectedCellIdentity, cellIdentityNr);
+        assertEquals(expectedSignalStrength, signalStrengthNr);
+    }
+
+    @Test
     public void testConvertDataCallResult() {
         // Test V1.0 SetupDataCallResult
         android.hardware.radio.V1_0.SetupDataCallResult result10 =
@@ -1579,17 +1651,26 @@
         result10.pcscf = "fd00:976a:c206:20::6   fd00:976a:c206:20::9    fd00:976a:c202:1d::9";
         result10.mtu = 1500;
 
-        DataCallResponse response = new DataCallResponse(0, -1, 0, 2, ApnSetting.PROTOCOL_IPV4V6,
-                "ifname",
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress("10.0.2.15"), 32),
-                        new LinkAddress("2607:fb90:a620:651d:eabe:f8da:c107:44be/64")),
-                Arrays.asList(NetworkUtils.numericToInetAddress("10.0.2.3"),
-                        NetworkUtils.numericToInetAddress("fd00:976a::9")),
-                Arrays.asList(NetworkUtils.numericToInetAddress("10.0.2.15"),
-                        NetworkUtils.numericToInetAddress("fe80::2")),
-                Arrays.asList(NetworkUtils.numericToInetAddress("fd00:976a:c206:20::6"),
-                        NetworkUtils.numericToInetAddress("fd00:976a:c206:20::9"),
-                        NetworkUtils.numericToInetAddress("fd00:976a:c202:1d::9")), 1500);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(0)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IPV4V6)
+                .setInterfaceName("ifname")
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress("10.0.2.15"), 32),
+                        new LinkAddress("2607:fb90:a620:651d:eabe:f8da:c107:44be/64")))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"),
+                        InetAddresses.parseNumericAddress("fd00:976a::9")))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.15"),
+                        InetAddresses.parseNumericAddress("fe80::2")))
+                .setPcscfAddresses(Arrays.asList(
+                        InetAddresses.parseNumericAddress("fd00:976a:c206:20::6"),
+                        InetAddresses.parseNumericAddress("fd00:976a:c206:20::9"),
+                        InetAddresses.parseNumericAddress("fd00:976a:c202:1d::9")))
+                .setMtu(1500)
+                .build();
 
         assertEquals(response, RIL.convertDataCallResult(result10));
 
@@ -1634,7 +1715,7 @@
         ws = new WorkSource();
         ws.createWorkChain().addNode(100, "foo").addNode(200, "bar");
         request = RILRequest.obtain(0, null, ws);
-        assertEquals("100:foo", request.getWorkSourceClientId());
+        assertEquals("WorkChain{(100, foo), (200, bar)}", request.getWorkSourceClientId());
     }
 
     @Test
@@ -1822,7 +1903,6 @@
     }
 
     @Test
-    @FlakyTest
     public void testSetupDataCall() throws Exception {
         DataProfile dp = new DataProfile.Builder()
                 .setProfileId(PROFILE_ID)
@@ -1866,7 +1946,9 @@
         assertEquals(APN_ENABLED, dpi.enabled);
         assertEquals(SUPPORTED_APNT_YPES_BITMAK, dpi.supportedApnTypesBitmap);
         assertEquals(ROAMING_PROTOCOL, ApnSetting.getProtocolIntFromString(dpi.protocol));
-        assertEquals(BEARER_BITMASK, dpi.bearerBitmap);
+        assertEquals(
+                BEARER_BITMASK,
+                ServiceState.convertBearerBitmaskToNetworkTypeBitmask(dpi.bearerBitmap >> 1));
         assertEquals(MTU, dpi.mtu);
     }
 
@@ -1955,4 +2037,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..ae5f6a3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
@@ -72,10 +72,10 @@
         ServiceState ss = new ServiceState();
 
         ss.setDataRegState(ServiceState.STATE_IN_SERVICE);
-        assertEquals(ServiceState.STATE_IN_SERVICE, ss.getDataRegState());
+        assertEquals(ServiceState.STATE_IN_SERVICE, ss.getDataRegistrationState());
 
         ss.setVoiceRegState(ServiceState.STATE_IN_SERVICE);
-        assertEquals(ServiceState.STATE_IN_SERVICE, ss.getVoiceRegState());
+        assertEquals(ServiceState.STATE_IN_SERVICE, ss.getState());
     }
 
     @SmallTest
@@ -171,6 +171,7 @@
         rats.add(new Pair<Integer, Boolean>(ServiceState.RIL_RADIO_TECHNOLOGY_GSM, false));
         rats.add(new Pair<Integer, Boolean>(ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA, false));
         rats.add(new Pair<Integer, Boolean>(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, false));
+        rats.add(new Pair<Integer, Boolean>(ServiceState.RIL_RADIO_TECHNOLOGY_NR, false));
 
         for (Pair<Integer, Boolean> rat : rats) {
             boolean isCdma = rat.second;
@@ -200,19 +201,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/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 1c68789..675f06f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -56,6 +56,7 @@
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.TimestampedValue;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.telephony.AccessNetworkConstants;
@@ -88,7 +89,6 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
-import android.util.TimestampedValue;
 
 import androidx.test.filters.FlakyTest;
 
@@ -108,6 +108,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 
@@ -302,6 +303,27 @@
                 com.android.internal.R.array.config_display_no_service_when_sim_unready,
                 new String[0]);
 
+        mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
+                new int[] {
+                    -110, /* SIGNAL_STRENGTH_POOR */
+                    -90, /* SIGNAL_STRENGTH_MODERATE */
+                    -80, /* SIGNAL_STRENGTH_GOOD */
+                    -65,  /* SIGNAL_STRENGTH_GREAT */
+                });
+        mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
+                new int[] {
+                    -16, /* SIGNAL_STRENGTH_POOR */
+                    -11, /* SIGNAL_STRENGTH_MODERATE */
+                    -9, /* SIGNAL_STRENGTH_GOOD */
+                    -7  /* SIGNAL_STRENGTH_GREAT */
+                });
+        mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
+                new int[] {
+                    -5, /* SIGNAL_STRENGTH_POOR */
+                    5, /* SIGNAL_STRENGTH_MODERATE */
+                    15, /* SIGNAL_STRENGTH_GOOD */
+                    30  /* SIGNAL_STRENGTH_GREAT */
+                });
         logd("ServiceStateTrackerTest -Setup!");
     }
 
@@ -449,7 +471,8 @@
 
     private CellInfoGsm getCellInfoGsm() {
         CellInfoGsm tmp = new CellInfoGsm();
-        tmp.setCellIdentity(new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst"));
+        tmp.setCellIdentity(new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst",
+                    Collections.emptyList()));
         tmp.setCellSignalStrength(new CellSignalStrengthGsm(-85, 2, 3));
         return tmp;
     }
@@ -682,6 +705,105 @@
     }
 
     @Test
+    public void test5gNrSignalStrengthReportingCriteria_UseSsRsrp() {
+        SignalStrength ss = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte(),
+                new CellSignalStrengthNr(
+                    -139, /** csiRsrp NONE */
+                    -20, /** csiRsrq NONE */
+                    -23, /** CsiSinr NONE */
+                    -44, /** SsRsrp SIGNAL_STRENGTH_GREAT */
+                    -20, /** SsRsrq NONE */
+                    -23) /** SsSinr NONE */
+         );
+
+        // SSRSRP = 1 << 0
+        mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
+                CellSignalStrengthNr.USE_SSRSRP);
+        sendCarrierConfigUpdate();
+        mSimulatedCommands.setSignalStrength(ss);
+        mSimulatedCommands.notifySignalStrength();
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+        assertEquals(CellSignalStrength.SIGNAL_STRENGTH_GREAT, sst.getSignalStrength().getLevel());
+    }
+
+    @Test
+    public void test5gNrSignalStrengthReportingCriteria_UseSsRsrpAndSsRsrq() {
+        SignalStrength ss = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte(),
+                new CellSignalStrengthNr(
+                    -139, /** csiRsrp NONE */
+                    -20, /** csiRsrq NONE */
+                    -23, /** CsiSinr NONE */
+                    -44, /** SsRsrp SIGNAL_STRENGTH_GREAT */
+                    -20, /** SsRsrq NONE */
+                    -23) /** SsSinr NONE */
+        );
+
+        // SSRSRP = 1 << 0 | SSSINR = 1 << 2
+        mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
+                CellSignalStrengthNr.USE_SSRSRP | CellSignalStrengthNr.USE_SSRSRQ);
+        sendCarrierConfigUpdate();
+        mSimulatedCommands.setSignalStrength(ss);
+        mSimulatedCommands.notifySignalStrength();
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+        assertEquals(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                sst.getSignalStrength().getLevel());
+    }
+
+    @Test
+    public void test5gNrSignalStrengthReportingCriteria_ConfiguredThresholds() {
+        SignalStrength ss = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte(),
+                new CellSignalStrengthNr(
+                    -139, /** csiRsrp NONE */
+                    -20, /** csiRsrq NONE */
+                    -23, /** CsiSinr NONE */
+                    -44, /** SsRsrp SIGNAL_STRENGTH_GREAT */
+                    -20, /** SsRsrq NONE */
+                    -23) /** SsSinr NONE */
+        );
+
+        // SSRSRP = 1 << 0
+        mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
+                CellSignalStrengthNr.USE_SSRSRP);
+        sendCarrierConfigUpdate();
+        mSimulatedCommands.setSignalStrength(ss);
+        mSimulatedCommands.notifySignalStrength();
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+        assertEquals(CellSignalStrength.SIGNAL_STRENGTH_GREAT, sst.getSignalStrength().getLevel());
+
+        int[] nrSsRsrpThresholds = {
+                -45, // SIGNAL_STRENGTH_POOR
+                -40, // SIGNAL_STRENGTH_MODERATE
+                -37, // SIGNAL_STRENGTH_GOOD
+                -34,  // SIGNAL_STRENGTH_GREAT
+        };
+        mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
+                nrSsRsrpThresholds);
+        mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
+                CellSignalStrengthNr.USE_SSRSRP);
+        sendCarrierConfigUpdate();
+        mSimulatedCommands.setSignalStrength(ss);
+        mSimulatedCommands.notifySignalStrength();
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+        assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR,
+                sst.getSignalStrength().getLevel());
+    }
+
+    @Test
     public void testWcdmaSignalStrengthReportingCriteria() {
         SignalStrength ss = new SignalStrength(
                 new CellSignalStrengthCdma(),
@@ -719,7 +841,7 @@
     // TODO(nharold): we probably should remove support for this procedure (GET_LOC)
     public void testGsmCellLocation() {
         CellIdentityGsm cellIdentityGsm = new CellIdentityGsm(
-                2, 3, 900, 5, "001", "01", "test", "tst");
+                2, 3, 900, 5, "001", "01", "test", "tst", Collections.emptyList());
 
         NetworkRegistrationInfo result = new NetworkRegistrationInfo.Builder()
                 .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
@@ -733,7 +855,7 @@
 
         waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
         WorkSource workSource = new WorkSource(Process.myUid(), mContext.getPackageName());
-        GsmCellLocation cl = (GsmCellLocation) sst.getCellLocation();
+        GsmCellLocation cl = (GsmCellLocation) sst.getCellIdentity().asCellLocation();
         assertEquals(2, cl.getLac());
         assertEquals(3, cl.getCid());
     }
@@ -757,7 +879,7 @@
 
         waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
         WorkSource workSource = new WorkSource(Process.myUid(), mContext.getPackageName());
-        CdmaCellLocation cl = (CdmaCellLocation) sst.getCellLocation();
+        CdmaCellLocation cl = (CdmaCellLocation) sst.getCellIdentity().asCellLocation();
         assertEquals(5, cl.getBaseStationLatitude());
         assertEquals(4, cl.getBaseStationLongitude());
     }
@@ -1389,7 +1511,7 @@
         doReturn(subId).when(mSubInfo).getSubscriptionId();
 
         doReturn(mSubInfo).when(mSubscriptionController).getActiveSubscriptionInfo(
-                anyInt(), anyString());
+                anyInt(), anyString(), nullable(String.class));
 
         final NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1421,7 +1543,7 @@
         sst.mSubId = subId;
         doReturn(subId).when(mSubInfo).getSubscriptionId();
         doReturn(mSubInfo).when(mSubscriptionController)
-                .getActiveSubscriptionInfo(anyInt(), anyString());
+                .getActiveSubscriptionInfo(anyInt(), anyString(), nullable(String.class));
 
         final NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1454,7 +1576,7 @@
         sst.mSubId = subId;
         doReturn(subId).when(mSubInfo).getSubscriptionId();
         doReturn(mSubInfo).when(mSubscriptionController)
-                .getActiveSubscriptionInfo(anyInt(), anyString());
+                .getActiveSubscriptionInfo(anyInt(), anyString(), nullable(String.class));
 
         final NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1486,7 +1608,7 @@
         sst.mSubId = subId;
         doReturn(subId).when(mSubInfo).getSubscriptionId();
         doReturn(mSubInfo).when(mSubscriptionController)
-                .getActiveSubscriptionInfo(anyInt(), anyString());
+                .getActiveSubscriptionInfo(anyInt(), anyString(), nullable(String.class));
 
         final NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1793,12 +1915,33 @@
         waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
     }
 
+    @Test
+    public void testPollStateOperatorWhileNotRegistered() {
+        final String[] oldOpNamesResult = new String[] { "Old carrier long", "Old carrier", "" };
+        final String[] badOpNamesResult = null;
+        sst.mPollingContext[0] = 1;
+        sst.sendMessage(sst.obtainMessage(
+                ServiceStateTracker.EVENT_POLL_STATE_OPERATOR,
+                new AsyncResult(sst.mPollingContext, oldOpNamesResult, null)));
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+        assertEquals(oldOpNamesResult[0], sst.getServiceState().getOperatorAlpha());
+
+        // if the device is not registered, the modem returns an invalid operator
+        sst.mPollingContext[0] = 1;
+        sst.sendMessage(sst.obtainMessage(
+                ServiceStateTracker.EVENT_POLL_STATE_OPERATOR,
+                new AsyncResult(sst.mPollingContext, badOpNamesResult, null)));
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+        assertEquals(null, sst.getServiceState().getOperatorAlpha());
+    }
+
     // Edge and GPRS are grouped under the same family and Edge has higher rate than GPRS.
     // Expect no rat update when move from E to G.
     @Test
     public void testRatRatchet() throws Exception {
         CellIdentityGsm cellIdentity =
-                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst");
+                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst",
+                        Collections.emptyList());
         // start on GPRS
         changeRegState(1, cellIdentity, 16, 1);
         assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
@@ -1816,14 +1959,16 @@
     @Test
     public void testRatRatchetWithCellChange() throws Exception {
         CellIdentityGsm cellIdentity =
-                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst");
+                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst",
+                        Collections.emptyList());
         // update data reg state to be in service
         changeRegState(1, cellIdentity, 16, 2);
         assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GSM, sst.mSS.getRilVoiceRadioTechnology());
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilDataRadioTechnology());
         // RAT: EDGE -> GPRS cell ID: 1 -> 2
-        cellIdentity = new CellIdentityGsm(0, 2, 900, 5, "001", "01", "test", "tst");
+        cellIdentity = new CellIdentityGsm(0, 2, 900, 5, "001", "01", "test", "tst",
+                Collections.emptyList());
         changeRegState(1, cellIdentity, 16, 1);
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilDataRadioTechnology());
 
@@ -1838,7 +1983,8 @@
     public void testRatRatchetWithCellChangeBeforeRatChange() throws Exception {
         // cell ID update
         CellIdentityGsm cellIdentity =
-                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst");
+                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst",
+                        Collections.emptyList());
         changeRegState(1, cellIdentity, 16, 2);
         assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilDataRadioTechnology());
@@ -1897,7 +2043,8 @@
     public void testPhyChanBandwidthUpdatedOnDataRegState() throws Exception {
         // Cell ID change should trigger hasLocationChanged.
         CellIdentityLte cellIdentity5 =
-                new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst");
+                new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst",
+                        Collections.emptyList(), null);
 
         sendPhyChanConfigChange(new int[] {10000});
         sendRegStateUpdateForLteCellId(cellIdentity5);
@@ -1908,7 +2055,8 @@
     public void testPhyChanBandwidthNotUpdatedWhenInvalidInCellIdentity() throws Exception {
         // Cell ID change should trigger hasLocationChanged.
         CellIdentityLte cellIdentityInv =
-                new CellIdentityLte(1, 1, 5, 1, 12345, "001", "01", "test", "tst");
+                new CellIdentityLte(1, 1, 5, 1, 12345, "001", "01", "test", "tst",
+                        Collections.emptyList(), null);
 
         sendPhyChanConfigChange(new int[] {10000});
         sendRegStateUpdateForLteCellId(cellIdentityInv);
@@ -1919,7 +2067,8 @@
     public void testPhyChanBandwidthPrefersCarrierAggregationReport() throws Exception {
         // Cell ID change should trigger hasLocationChanged.
         CellIdentityLte cellIdentity10 =
-                new CellIdentityLte(1, 1, 5, 1, 10000, "001", "01", "test", "tst");
+                new CellIdentityLte(1, 1, 5, 1, 10000, "001", "01", "test", "tst",
+                        Collections.emptyList(), null);
 
         sendPhyChanConfigChange(new int[] {10000, 5000});
         sendRegStateUpdateForLteCellId(cellIdentity10);
@@ -1930,7 +2079,8 @@
     public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() throws Exception {
         // LTE Cell with bandwidth = 10000
         CellIdentityLte cellIdentity10 =
-                new CellIdentityLte(1, 1, 1, 1, 10000, "1", "1", "test", "tst");
+                new CellIdentityLte(1, 1, 1, 1, 10000, "1", "1", "test", "tst",
+                        Collections.emptyList(), null);
 
         sendRegStateUpdateForLteCellId(cellIdentity10);
         assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths()));
@@ -1977,7 +2127,8 @@
 
         // Start state: Cell data only LTE + IWLAN
         CellIdentityLte cellIdentity =
-                new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst");
+                new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst",
+                        Collections.emptyList(), null);
         changeRegStateWithIwlan(
                 // WWAN
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME, cellIdentity,
@@ -2132,7 +2283,8 @@
         sst.mSS = ss;
 
         CellIdentityLte cellId =
-                new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst");
+                new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst",
+                        Collections.emptyList(), null);
         LteVopsSupportInfo lteVopsSupportInfo =
                 new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
                     LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java
index 04d8b0d..1fa2154 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java
@@ -20,6 +20,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
 import android.telephony.CellInfo;
 import android.telephony.CellSignalStrength;
 import android.telephony.CellSignalStrengthCdma;
@@ -42,6 +44,29 @@
 @SmallTest
 @RunWith(JUnit4.class)
 public class SignalStrengthTest {
+    private static final int[] DEFAULT_LTE_RSRP_THRESHOLDS = {
+            -128,  // SIGNAL_STRENGTH_POOR
+            -118,  // SIGNAL_STRENGTH_MODERATE
+            -108,  // SIGNAL_STRENGTH_GOOD
+            -98 }; // SIGNAL_STRENGTH_GREAT
+
+    private static final int[] DEFAULT_LTE_RSRQ_THRESHOLDS = {
+            -19,   // SIGNAL_STRENGTH_POOR
+            -17,   // SIGNAL_STRENGTH_MODERATE
+            -14,   // SIGNAL_STRENGTH_GOOD
+            -12 }; // SIGNAL_STRENGTH_GREAT
+
+    private static final int[] DEFAULT_LTE_RSSNR_THRESHOLDS = {
+            -30,   // SIGNAL_STRENGTH_POOR
+            10,    // SIGNAL_STRENGTH_MODERATE
+            45,    // SIGNAL_STRENGTH_GOOD
+            130 }; // SIGNAL_STRENGTH_GREAT
+
+    private static final int[] DEFAULT_5G_NR_SSRSRP_THRESHOLDS = {
+            -125,  // SIGNAL_STRENGTH_POOR
+            -115,  // SIGNAL_STRENGTH_MODERATE
+            -105,  // SIGNAL_STRENGTH_GOOD
+            -95 }; // SIGNAL_STRENGTH_GREAT
 
     @Test
     public void testDefaults() throws Exception {
@@ -71,6 +96,23 @@
                 new CellSignalStrengthLte(-85, -91, -6, -10, 12, 1),
                 new CellSignalStrengthNr(-91, -6, 3, -80, -7, 4));
         assertParcelingIsLossless(s);
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY,
+                DEFAULT_LTE_RSRQ_THRESHOLDS);
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
+                DEFAULT_LTE_RSRP_THRESHOLDS);
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY,
+                DEFAULT_LTE_RSSNR_THRESHOLDS);
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
+                DEFAULT_5G_NR_SSRSRP_THRESHOLDS);
+
+        s.updateLevel(bundle, null);
+        assertParcelingIsLossless(s);
     }
 
     private void assertParcelingIsLossless(SignalStrength ssi) throws Exception {
@@ -116,5 +158,247 @@
         assertTrue(css.contains(cdma));
         assertTrue(css.contains(lte));
     }
+
+    private static SignalStrength createSignalStrengthLteReportRsrq(int lteRsrp, int lteRsrq) {
+
+        CellSignalStrengthLte lte = new CellSignalStrengthLte(
+                -89,                   // rssi
+                lteRsrp,               // rsrp
+                lteRsrq,               // rsrq
+                -25,                   // rssnr
+                CellInfo.UNAVAILABLE,  // cqi
+                CellInfo.UNAVAILABLE); // timingAdvance
+
+        SignalStrength signalStrength = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                lte,
+                new CellSignalStrengthNr());
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putInt(
+                CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
+                CellSignalStrengthLte.USE_RSRP | CellSignalStrengthLte.USE_RSRQ);
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY,
+                DEFAULT_LTE_RSRQ_THRESHOLDS);
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
+                DEFAULT_LTE_RSRP_THRESHOLDS);
+        signalStrength.updateLevel(bundle, null);
+        return signalStrength;
+    }
+
+    private static SignalStrength createSignalStrengthLteReportRssnr(int lteRsrp, int lteRssnr) {
+
+        CellSignalStrengthLte lte = new CellSignalStrengthLte(
+                -89,                   // rssi
+                lteRsrp,               // rsrp
+                15,                    // rsrq
+                lteRssnr,              // rssnr
+                CellInfo.UNAVAILABLE,  // cqi
+                CellInfo.UNAVAILABLE); // timingAdvance
+
+        SignalStrength signalStrength = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                lte,
+                new CellSignalStrengthNr());
+
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putInt(
+                CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
+                CellSignalStrengthLte.USE_RSRP | CellSignalStrengthLte.USE_RSSNR);
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
+                DEFAULT_LTE_RSRP_THRESHOLDS);
+        bundle.putIntArray(
+                CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY,
+                DEFAULT_LTE_RSSNR_THRESHOLDS);
+        signalStrength.updateLevel(bundle, null);
+        return signalStrength;
+    }
+
+    @Test
+    public void testValidateInput() throws Exception {
+
+        SignalStrength ss;
+
+        // Input value of RSRQ: 4[dB]
+        ss = createSignalStrengthLteReportRsrq(-60, 4);
+        assertEquals(SignalStrength.INVALID, ss.getLteRsrq());
+
+        // Input value of RSRQ: 3[dB]
+        ss = createSignalStrengthLteReportRsrq(-60, 3);
+        assertEquals(3, ss.getLteRsrq());
+
+        // Input value of RSRQ: -34[dB]
+        ss = createSignalStrengthLteReportRsrq(-60, -34);
+        assertEquals(-34, ss.getLteRsrq());
+
+        // Input value of RSRQ: -35[dB]
+        ss = createSignalStrengthLteReportRsrq(-60, -35);
+        assertEquals(SignalStrength.INVALID, ss.getLteRsrq());
+
+        // Input value of RSSNR: 301[dB]
+        ss = createSignalStrengthLteReportRssnr(-60, 301);
+        assertEquals(SignalStrength.INVALID, ss.getLteRssnr());
+
+        // Input value of RSSNR: 300[dB]
+        ss = createSignalStrengthLteReportRssnr(-60, 300);
+        assertEquals(300, ss.getLteRssnr());
+
+        // Input value of RSSNR: -200[dB]
+        ss = createSignalStrengthLteReportRssnr(60, -200);
+        assertEquals(-200, ss.getLteRssnr());
+
+        // Input value of RSSNR: -201[dB]
+        ss = createSignalStrengthLteReportRssnr(60, -201);
+        assertEquals(SignalStrength.INVALID, ss.getLteRssnr());
+    }
+
+    @Test
+    public void testRsrqThresholds_rsrp_great() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-98, -34).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRsrq(-98, -19).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRsrq(-98, -17).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD,
+                createSignalStrengthLteReportRsrq(-98, -14).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT,
+                createSignalStrengthLteReportRsrq(-98, -12).getLteLevel());
+    }
+
+    @Test
+    public void testRsrqThresholds_rsrp_good() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-108, -34).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRsrq(-108, -19).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRsrq(-108, -17).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD,
+                createSignalStrengthLteReportRsrq(-108, -14).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD,
+                createSignalStrengthLteReportRsrq(-108, -12).getLteLevel());
+    }
+
+    @Test
+    public void testRsrqThresholds_rsrp_moderate() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-118, -34).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRsrq(-118, -19).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRsrq(-118, -17).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRsrq(-118, -14).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRsrq(-118, -12).getLteLevel());
+    }
+
+    @Test
+    public void testRsrqThresholds_rsrp_poor() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-128, -34).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRsrq(-128, -19).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRsrq(-128, -17).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRsrq(-128, -14).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRsrq(-128, -12).getLteLevel());
+    }
+
+    @Test
+    public void testRsrqThresholds_rsrp_unknown() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-138, -34).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-138, -19).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-138, -17).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-138, -14).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRsrq(-138, -12).getLteLevel());
+    }
+
+    @Test
+    public void testRssnrThresholds_rsrp_great() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-98, -200).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRssnr(-98, -30).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRssnr(-98, 10).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD,
+                createSignalStrengthLteReportRssnr(-98, 45).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT,
+                createSignalStrengthLteReportRssnr(-98, 130).getLteLevel());
+    }
+
+    @Test
+    public void testRssnrThresholds_rsrp_good() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-108, -200).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRssnr(-108, -30).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRssnr(-108, 10).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD,
+                createSignalStrengthLteReportRssnr(-108, 45).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD,
+                createSignalStrengthLteReportRssnr(-108, 130).getLteLevel());
+    }
+
+    @Test
+    public void testRssnrThresholds_rsrp_moderate() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-118, -200).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRssnr(-118, -30).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRssnr(-118, 10).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRssnr(-118, 45).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE,
+                createSignalStrengthLteReportRssnr(-118, 130).getLteLevel());
+    }
+
+    @Test
+    public void testRssnrThresholds_rsrp_poor() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-128, -200).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRssnr(-128, -30).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRssnr(-128, 10).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRssnr(-128, 45).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR,
+                createSignalStrengthLteReportRssnr(-128, 130).getLteLevel());
+    }
+
+    @Test
+    public void testRssnrThresholds_rsrp_unknown() throws Exception {
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-138, -200).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-138, -30).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-138, 10).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-138, 45).getLteLevel());
+        assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+                createSignalStrengthLteReportRssnr(-138, 130).getLteLevel());
+    }
 }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java
new file mode 100644
index 0000000..ddf5bcd
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 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 com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.telephony.SignalThresholdInfo;
+
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(JUnit4.class)
+public class SignalThresholdInfoTest extends TestCase {
+    private static final int HYSTERESIS_DB = 2;
+    private static final int HYSTERESIS_MS = 30;
+    private static final int[] SSRSRP_THRESHOLDS = new int[] {-30, 10, 45, 130};
+
+    private final int[] mRssiThresholds = new int[] {-109, -103, -97, -89};
+    private final int[] mRscpThresholds = new int[] {-115, -105, -95, -85};
+    private final int[] mRsrpThresholds = new int[] {-128, -118, -108, -98};
+    private final int[] mRsrqThresholds = new int[] {-19, -17, -14, -12};
+    private final int[] mRssnrThresholds = new int[] {-30, 10, 45, 130};
+    private final int[][] mThresholds = new int[5][];
+
+    @Test
+    @SmallTest
+    public void testSignalThresholdInfo() throws Exception {
+        SignalThresholdInfo signalThresholdInfo = new SignalThresholdInfo(
+                SignalThresholdInfo.SIGNAL_SSRSRP,
+                HYSTERESIS_MS,
+                HYSTERESIS_DB,
+                SSRSRP_THRESHOLDS,
+                false);
+
+        assertEquals(SignalThresholdInfo.SIGNAL_SSRSRP,
+                signalThresholdInfo.getSignalMeasurement());
+        assertEquals(HYSTERESIS_MS, signalThresholdInfo.getHysteresisMs());
+        assertEquals(HYSTERESIS_DB, signalThresholdInfo.getHysteresisDb());
+        assertEquals(Arrays.toString(SSRSRP_THRESHOLDS), Arrays.toString(
+                signalThresholdInfo.getThresholds()));
+        assertFalse(signalThresholdInfo.isEnabled());
+    }
+
+    @Test
+    @SmallTest
+    public void testDefaultThresholdsConstruction() {
+        setThresholds();
+        ArrayList<SignalThresholdInfo> stList = setSignalThresholdInfoConstructor();
+
+        int count = 0;
+        for (SignalThresholdInfo st : stList) {
+            assertThat(st.getThresholds()).isEqualTo(mThresholds[count]);
+            count++;
+        }
+    }
+
+    @Test
+    @SmallTest
+    public void testDefaultThresholdsParcel() {
+        ArrayList<SignalThresholdInfo> stList = setSignalThresholdInfoConstructor();
+
+        for (SignalThresholdInfo st : stList) {
+            Parcel p = Parcel.obtain();
+            st.writeToParcel(p, 0);
+            p.setDataPosition(0);
+
+            SignalThresholdInfo newSt = SignalThresholdInfo.CREATOR.createFromParcel(p);
+            assertThat(newSt).isEqualTo(st);
+        }
+    }
+
+    @Test
+    @SmallTest
+    public void testGetSignalThresholdInfo() {
+        ArrayList<SignalThresholdInfo> stList = new ArrayList<>();
+        stList.add(new SignalThresholdInfo(0, 0, 0, null, false));
+        stList.add(new SignalThresholdInfo(SignalThresholdInfo.SIGNAL_RSSI, HYSTERESIS_MS,
+                HYSTERESIS_DB, mRssiThresholds, false));
+
+        assertThat(stList.get(0).getThresholds()).isEqualTo(null);
+        assertThat(stList.get(1).getSignalMeasurement()).isEqualTo(SignalThresholdInfo.SIGNAL_RSSI);
+        assertThat(stList.get(1).getThresholds()).isEqualTo(mRssiThresholds);
+    }
+
+    @Test
+    @SmallTest
+    public void testEqualsSignalThresholdInfo() {
+        final int[] dummyThresholds = new int[] {-100, -1, 1, 100};
+        SignalThresholdInfo st1 = new SignalThresholdInfo(1, HYSTERESIS_MS, HYSTERESIS_DB,
+                mRssiThresholds, false);
+        SignalThresholdInfo st2 = new SignalThresholdInfo(2, HYSTERESIS_MS, HYSTERESIS_DB,
+                mRssiThresholds, false);
+        SignalThresholdInfo st3 = new SignalThresholdInfo(1, HYSTERESIS_MS, HYSTERESIS_DB,
+                dummyThresholds, false);
+        SignalThresholdInfo st4 = new SignalThresholdInfo(1, HYSTERESIS_MS, HYSTERESIS_DB,
+                mRssiThresholds, false);
+
+        //Return true if all SignalThresholdInfo values match.
+        assertTrue(st1.equals(st1));
+        assertFalse(st1.equals(st2));
+        assertFalse(st1.equals(st3));
+        assertTrue(st1.equals(st4));
+        //Return false if the object of argument is other than SignalThresholdInfo.
+        assertFalse(st1.equals(new String("test")));
+    }
+
+    private void setThresholds() {
+        mThresholds[0] = mRssiThresholds;
+        mThresholds[1] = mRscpThresholds;
+        mThresholds[2] = mRsrpThresholds;
+        mThresholds[3] = mRsrqThresholds;
+        mThresholds[4] = mRssnrThresholds;
+    }
+
+    private ArrayList<SignalThresholdInfo> setSignalThresholdInfoConstructor() {
+        ArrayList<SignalThresholdInfo> stList = new ArrayList<>();
+        stList.add(new SignalThresholdInfo(SignalThresholdInfo.SIGNAL_RSSI, HYSTERESIS_MS,
+                HYSTERESIS_DB, mRssiThresholds, false));
+        stList.add(new SignalThresholdInfo(SignalThresholdInfo.SIGNAL_RSCP, HYSTERESIS_MS,
+                HYSTERESIS_DB, mRscpThresholds, false));
+        stList.add(new SignalThresholdInfo(SignalThresholdInfo.SIGNAL_RSRP, HYSTERESIS_MS,
+                HYSTERESIS_DB, mRsrpThresholds, false));
+        stList.add(new SignalThresholdInfo(SignalThresholdInfo.SIGNAL_RSRQ, HYSTERESIS_MS,
+                HYSTERESIS_DB, mRsrqThresholds, false));
+        stList.add(new SignalThresholdInfo(SignalThresholdInfo.SIGNAL_RSSNR, HYSTERESIS_MS,
+                HYSTERESIS_DB, mRssnrThresholds, false));
+
+        return stList;
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimSlotCapabilityTest.java b/tests/telephonytests/src/com/android/internal/telephony/SimSlotCapabilityTest.java
new file mode 100644
index 0000000..8763c82
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimSlotCapabilityTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.Parcel;
+import android.telephony.SimSlotCapability;
+
+import org.junit.Test;
+
+public class SimSlotCapabilityTest {
+    @Test
+    public void basicTests() {
+        int physicalSlotId = 0;
+        int slotType = SimSlotCapability.SLOT_TYPE_UICC;
+
+        SimSlotCapability capability = new SimSlotCapability(physicalSlotId, slotType);
+        assertEquals(physicalSlotId, capability.getPhysicalSlotIndex());
+        assertEquals(slotType, capability.getSlotType());
+
+        SimSlotCapability toCompare = new SimSlotCapability(physicalSlotId + 1,
+                SimSlotCapability.SLOT_TYPE_IUICC);
+        assertEquals(capability, new SimSlotCapability(physicalSlotId, slotType));
+        assertNotEquals(capability, toCompare);
+    }
+
+    @Test
+    public void parcelReadWrite() {
+        int physicalSlotId = 0;
+        int slotType = SimSlotCapability.SLOT_TYPE_EUICC;
+
+        SimSlotCapability capability = new SimSlotCapability(physicalSlotId, slotType);
+
+        Parcel parcel = Parcel.obtain();
+        capability.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        SimSlotCapability toCompare = SimSlotCapability.CREATOR.createFromParcel(parcel);
+
+        assertEquals(physicalSlotId, capability.getPhysicalSlotIndex());
+        assertEquals(slotType, capability.getSlotType());
+        assertEquals(capability, toCompare);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
similarity index 98%
rename from src/java/com/android/internal/telephony/test/SimulatedCommands.java
rename to tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
index db581b2..02ab55b 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.test;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.radio.V1_0.DataRegStateResult;
 import android.hardware.radio.V1_0.SetupDataCallResult;
 import android.hardware.radio.V1_0.VoiceRegStateResult;
@@ -42,10 +43,11 @@
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.NetworkScanRequest;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.telephony.data.DataCallResponse;
 import android.telephony.data.DataProfile;
 import android.telephony.emergency.EmergencyNumber;
@@ -68,8 +70,7 @@
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.IccSlotStatus;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -1179,6 +1180,14 @@
             }
         }
 
+        // Store different cids to simulate concurrent IMS and default data calls
+        if ((dataProfile.getSupportedApnTypesBitmask() & ApnSetting.TYPE_IMS)
+            == ApnSetting.TYPE_IMS) {
+            mSetupDataCallResult.cid = 0;
+        } else {
+            mSetupDataCallResult.cid = 1;
+        }
+
         DataCallResponse response = RIL.convertDataCallResult(mSetupDataCallResult);
         if (mDcSuccess) {
             resultSuccess(result, response);
@@ -1396,8 +1405,9 @@
     @Override
     public void exitEmergencyCallbackMode(Message result) {unimplemented(result);}
     @Override
-    public void setNetworkSelectionModeManual(
-            String operatorNumeric, Message result) {unimplemented(result);}
+    public void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message result) {
+        unimplemented(result);
+    }
 
     /**
      * Queries whether the current network selection mode is automatic
@@ -1796,6 +1806,13 @@
         resultSuccess(response, null);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void sendCdmaSMSExpectMore(byte[] pdu, Message response){
+    }
+
     @Override
     public void setCdmaBroadcastActivation(boolean activate, Message response) {
         unimplemented(response);
@@ -2239,8 +2256,8 @@
     }
 
     @Override
-    public void setSignalStrengthReportingCriteria(int hysteresisMs, int hysteresisDb,
-            int[] thresholdsDbm, int ran, Message result) {
+    public void setSignalStrengthReportingCriteria(SignalThresholdInfo signalThresholdInfo,
+            int ran, Message result) {
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
similarity index 97%
rename from src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
rename to tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index c550f2c..55a517b 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -16,12 +16,14 @@
 
 package com.android.internal.telephony.test;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.KeepalivePacketData;
 import android.net.LinkProperties;
 import android.os.Handler;
 import android.os.Message;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.SignalThresholdInfo;
 import android.telephony.TelephonyManager;
 import android.telephony.data.DataProfile;
 import android.telephony.emergency.EmergencyNumber;
@@ -32,8 +34,6 @@
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
 public class SimulatedCommandsVerifier implements CommandsInterface {
     private static SimulatedCommandsVerifier sInstance;
 
@@ -842,6 +842,11 @@
     }
 
     @Override
+    public void sendCdmaSMSExpectMore(byte[] pdu, Message response) {
+
+    }
+
+    @Override
     public void sendImsGsmSms(String smscPDU, String pdu, int retry, int messageRef,
                               Message response) {
 
@@ -948,7 +953,7 @@
     }
 
     @Override
-    public void setNetworkSelectionModeManual(String operatorNumeric, Message response) {
+    public void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message response) {
 
     }
 
@@ -1127,7 +1132,7 @@
     }
 
     @Override
-    public void sendCDMAFeatureCode(String FeatureCode, Message response) {
+    public void sendCDMAFeatureCode(String featureCode, Message response) {
 
     }
 
@@ -1260,7 +1265,7 @@
     }
 
     @Override
-    public void iccOpenLogicalChannel(String AID, int p2, Message response) {
+    public void iccOpenLogicalChannel(String aid, int p2, Message response) {
 
     }
 
@@ -1393,8 +1398,8 @@
     }
 
     @Override
-    public void setSignalStrengthReportingCriteria(int hysteresisMs, int hysteresisDb,
-            int[] thresholdsDbm, int ran, Message result) {
+    public void setSignalStrengthReportingCriteria(SignalThresholdInfo signalThresholdInfo,
+            int ran, Message result) {
     }
 
     @Override
@@ -1443,4 +1448,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/src/java/com/android/internal/telephony/test/SimulatedGsmCallState.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedGsmCallState.java
similarity index 99%
rename from src/java/com/android/internal/telephony/test/SimulatedGsmCallState.java
rename to tests/telephonytests/src/com/android/internal/telephony/SimulatedGsmCallState.java
index 72e2d93..53fd987 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedGsmCallState.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedGsmCallState.java
@@ -16,16 +16,15 @@
 
 package com.android.internal.telephony.test;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.ATParseEx;
 import com.android.internal.telephony.DriverCall;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java
index 32dfef8..bd963ef 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsMessageBodyTest.java
@@ -16,18 +16,11 @@
 
 package com.android.internal.telephony;
 
-import android.telephony.SmsMessage;
 import android.telephony.TelephonyManager;
-import android.telephony.Rlog;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 
-import com.android.internal.telephony.SmsConstants;
-
-import java.util.Random;
+import com.android.telephony.Rlog;
 
 /**
  * Test cases to verify selection of the optimal 7 bit encoding tables
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java
index e427574..dd79f69 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java
@@ -39,7 +39,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-public class SmsPermissionsTest {
+public class SmsPermissionsTest extends TelephonyTest {
     private static final String PACKAGE = "com.example.package";
     private static final String MESSAGE = "msg";
 
@@ -59,6 +59,8 @@
 
     @Before
     public void setUp() throws Exception {
+        super.setUp("SmsPermissionsTest");
+
         MockitoAnnotations.initMocks(this);
         mHandlerThread = new HandlerThread("IccSmsInterfaceManagerTest");
         mHandlerThread.start();
@@ -89,6 +91,8 @@
     @After
     public void tearDown() throws Exception {
         mHandlerThread.quit();
+        mHandlerThread.join();
+        super.tearDown();
     }
 
     @Test
@@ -196,6 +200,8 @@
 
     @Test
     public void testCheckCallingOrSelfCanGetSmscAddressPermissions_noPermissions() {
+        Mockito.when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(
+                mTelephonyManager);
         Mockito.when(mMockContext.checkCallingOrSelfPermission(
                     Manifest.permission.READ_PRIVILEGED_PHONE_STATE))
                 .thenReturn(PERMISSION_DENIED);
@@ -221,9 +227,10 @@
 
     @Test
     public void testCheckCallingOrSelfCanSetSmscAddressPermissions_noPermissions() {
+        Mockito.when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(
+                mTelephonyManager);
         Mockito.when(mMockContext.checkCallingOrSelfPermission(
-                    Manifest.permission.MODIFY_PHONE_STATE))
-                .thenReturn(PERMISSION_DENIED);
+                Manifest.permission.MODIFY_PHONE_STATE)).thenReturn(PERMISSION_DENIED);
         assertFalse(mSmsPermissionsTest.checkCallingOrSelfCanSetSmscAddress(PACKAGE, MESSAGE));
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index ce3281d..0399245 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -24,7 +24,6 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
@@ -60,11 +59,13 @@
 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;
     private static final int DUAL_SIM = 2;
     private String mCallingPackage;
+    private String mCallingFeature;
     private SubscriptionController mSubscriptionControllerUT;
     private MockContentResolver mMockContentResolver;
     private FakeTelephonyProvider mFakeTelephonyProvider;
@@ -94,11 +95,10 @@
 
         mSubscriptionControllerUT = SubscriptionController.init(mContext);
         mCallingPackage = mContext.getOpPackageName();
+        mCallingFeature = null;
 
         doReturn(1).when(mProxyController).getMaxRafSupported();
-        mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[]{5});
-
-        mSubscriptionControllerUT.updatePhonesAvailability(new Phone[] {mPhone});
+        mContextFixture.putIntArrayResource(android.R.array.simColors, new int[]{5});
     }
 
     @After
@@ -130,18 +130,20 @@
     @Test @SmallTest
     public void testInsertSim() {
         //verify there is no sim inserted in the SubscriptionManager
-        assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+        assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage,
+                mCallingFeature));
 
         int slotID = 0;
         //insert one Subscription Info
         mSubscriptionControllerUT.addSubInfoRecord("test", slotID);
 
         //verify there is one sim
-        assertEquals(1, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+        assertEquals(1, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage,
+                mCallingFeature));
 
         //sanity for slot id and sub id
         List<SubscriptionInfo> mSubList = mSubscriptionControllerUT
-                .getActiveSubscriptionInfoList(mCallingPackage);
+                .getActiveSubscriptionInfoList(mCallingPackage, mCallingFeature);
         assertTrue(mSubList != null && mSubList.size() > 0);
         for (int i = 0; i < mSubList.size(); i++) {
             assertTrue(SubscriptionManager.isValidSubscriptionId(
@@ -166,7 +168,7 @@
 
         /* Getting, there is no direct getter function for each fields of property */
         SubscriptionInfo subInfo = mSubscriptionControllerUT
-                .getActiveSubscriptionInfo(subID, mCallingPackage);
+                .getActiveSubscriptionInfo(subID, mCallingPackage, mCallingFeature);
 
         /* Setting */
         mSubscriptionControllerUT.setDisplayNameUsingSrc(disName, subID,
@@ -177,7 +179,7 @@
         mSubscriptionControllerUT.setOpportunistic(isOpportunistic, subID, mCallingPackage);
 
         subInfo = mSubscriptionControllerUT
-            .getActiveSubscriptionInfo(subID, mCallingPackage);
+            .getActiveSubscriptionInfo(subID, mCallingPackage, mCallingFeature);
 
         assertNotNull(subInfo);
         assertEquals(dataRoaming, subInfo.getDataRoaming());
@@ -204,10 +206,10 @@
 
         /* 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);
+                .getActiveSubscriptionInfo(subID, mCallingPackage, mCallingFeature);
         assertNotNull(subInfo);
         assertEquals(disName, subInfo.getDisplayName());
         assertEquals(nameSource, subInfo.getNameSource());
@@ -254,7 +256,7 @@
         mSubscriptionControllerUT.setMccMnc(mCcMncVERIZON, 1);
 
         SubscriptionInfo subInfo = mSubscriptionControllerUT
-                .getActiveSubscriptionInfo(1, mCallingPackage);
+                .getActiveSubscriptionInfo(1, mCallingPackage, mCallingFeature);
         assertNotNull(subInfo);
         assertEquals(Integer.parseInt(mCcMncVERIZON.substring(0, 3)), subInfo.getMcc());
         assertEquals(Integer.parseInt(mCcMncVERIZON.substring(3)), subInfo.getMnc());
@@ -273,7 +275,7 @@
         mSubscriptionControllerUT.setCarrierId(carrierId, 1);
 
         SubscriptionInfo subInfo = mSubscriptionControllerUT
-                .getActiveSubscriptionInfo(1, mCallingPackage);
+                .getActiveSubscriptionInfo(1, mCallingPackage, mCallingFeature);
         assertNotNull(subInfo);
         assertEquals(carrierId, subInfo.getCarrierId());
 
@@ -360,27 +362,32 @@
         assertEquals("1", mSubscriptionControllerUT.getSubscriptionProperty(
                 subID,
                 SubscriptionManager.ENHANCED_4G_MODE_ENABLED,
-                mCallingPackage));
+                mCallingPackage,
+                mCallingFeature));
 
         assertEquals("0", mSubscriptionControllerUT.getSubscriptionProperty(
                 subID,
                 SubscriptionManager.VT_IMS_ENABLED,
-                mCallingPackage));
+                mCallingPackage,
+                mCallingFeature));
 
         assertEquals("1", mSubscriptionControllerUT.getSubscriptionProperty(
                 subID,
                 SubscriptionManager.WFC_IMS_ENABLED,
-                mCallingPackage));
+                mCallingPackage,
+                mCallingFeature));
 
         assertEquals("2", mSubscriptionControllerUT.getSubscriptionProperty(
                 subID,
                 SubscriptionManager.WFC_IMS_MODE,
-                mCallingPackage));
+                mCallingPackage,
+                mCallingFeature));
 
         assertEquals("3", mSubscriptionControllerUT.getSubscriptionProperty(
                 subID,
                 SubscriptionManager.WFC_IMS_ROAMING_MODE,
-                mCallingPackage));
+                mCallingPackage,
+                mCallingFeature));
     }
 
     @Test
@@ -449,7 +456,7 @@
         // Neither sub1 or sub2 are opportunistic. So getOpportunisticSubscriptions
         // should return empty list and no callback triggered.
         List<SubscriptionInfo> opptSubList = mSubscriptionControllerUT
-                .getOpportunisticSubscriptions(mCallingPackage);
+                .getOpportunisticSubscriptions(mCallingPackage, mCallingFeature);
 
         assertTrue(opptSubList.isEmpty());
         verify(mTelephonyRegisteryMock, times(0))
@@ -461,18 +468,18 @@
         verify(mTelephonyRegisteryMock, times(1))
                 .notifyOpportunisticSubscriptionInfoChanged();
         opptSubList = mSubscriptionControllerUT
-                .getOpportunisticSubscriptions(mCallingPackage);
+                .getOpportunisticSubscriptions(mCallingPackage, mCallingFeature);
         assertEquals(1, opptSubList.size());
         assertEquals("test2", opptSubList.get(0).getIccId());
 
         // 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();
     }
@@ -482,7 +489,8 @@
         makeThisDeviceMultiSimCapable();
 
         // verify there are no sim's in the system.
-        assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+        assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage,
+                mCallingFeature));
 
         addAndVerifyRemoteSimAddition(1, 0);
     }
@@ -490,14 +498,15 @@
     private void addAndVerifyRemoteSimAddition(int num, int numOfCurrentSubs) {
         // Verify the number of current subs in the system
         assertEquals(numOfCurrentSubs,
-                mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+                mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage, mCallingFeature));
 
         // if there are current subs in the system, get that info
         List<SubscriptionInfo> mSubList;
         ArrayList<String> macAddresses = new ArrayList<>();
         ArrayList<String> displayNames = new ArrayList<>();
         if (numOfCurrentSubs > 0) {
-            mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage);
+            mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage,
+                    mCallingFeature);
             assertNotNull(mSubList);
             assertEquals(numOfCurrentSubs, mSubList.size());
             for (SubscriptionInfo info : mSubList) {
@@ -537,7 +546,8 @@
             assertEquals(expectedNumOfSubs, subIdsList.size());
 
             // validate slot index, sub id etc
-            mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage);
+            mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage,
+                    mCallingFeature);
             assertNotNull(mSubList);
             assertEquals(expectedNumOfSubs, mSubList.size());
 
@@ -567,7 +577,8 @@
         makeThisDeviceMultiSimCapable();
 
         // verify that there are no subscription info records
-        assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+        assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage,
+                mCallingFeature));
         Map<Integer, ArrayList<Integer>> slotIndexToSubsMap =
                 mSubscriptionControllerUT.getSlotIndexToSubIdsMap();
         assertNotNull(slotIndexToSubsMap);
@@ -709,8 +720,9 @@
                 subIdList, mContext.getOpPackageName());
         assertNotEquals(null, groupId);
 
-        List<SubscriptionInfo> subInfoList = mSubscriptionControllerUT
-                .getActiveSubscriptionInfoList(mContext.getOpPackageName());
+        List<SubscriptionInfo> subInfoList =
+                mSubscriptionControllerUT.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
+                        null);
 
         // Put sub3 into slot 1 to make sub2 inactive.
         mContextFixture.addCallingOrSelfPermission(
@@ -731,6 +743,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", null);
+        assertEquals(2, infoList.size());
+    }
+
+    @Test
+    @SmallTest
     public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
         testInsertSim();
         // Adding a second profile and mark as embedded.
@@ -757,7 +820,7 @@
         mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                 new int[] {2}, groupId, "packageName1");
         List<SubscriptionInfo> infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
-                groupId, "packageName1");
+                groupId, "packageName1", null);
         assertEquals(2, infoList.size());
         assertEquals(1, infoList.get(0).getSubscriptionId());
         assertEquals(2, infoList.get(1).getSubscriptionId());
@@ -765,7 +828,7 @@
         mSubscriptionControllerUT.removeSubscriptionsFromGroup(
                 new int[] {2}, groupId, "packageName1");
         infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
-                groupId, "packageName1");
+                groupId, "packageName1", null);
         assertEquals(1, infoList.size());
         assertEquals(1, infoList.get(0).getSubscriptionId());
 
@@ -785,7 +848,7 @@
         mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                 new int[] {2}, groupId, "packageName1");
         infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
-                groupId, "packageName1");
+                groupId, "packageName1", null);
         assertEquals(2, infoList.size());
         assertEquals(1, infoList.get(0).getSubscriptionId());
         assertEquals(2, infoList.get(1).getSubscriptionId());
@@ -793,7 +856,7 @@
         mSubscriptionControllerUT.removeSubscriptionsFromGroup(
                 new int[] {2}, groupId, "packageName1");
         infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
-                groupId, "packageName1");
+                groupId, "packageName1", null);
         assertEquals(1, infoList.size());
         assertEquals(1, infoList.get(0).getSubscriptionId());
     }
@@ -828,7 +891,7 @@
         verify(mTelephonyRegisteryMock, times(2))
                 .notifyOpportunisticSubscriptionInfoChanged();
         List<SubscriptionInfo> opptSubList = mSubscriptionControllerUT
-                .getOpportunisticSubscriptions(mCallingPackage);
+                .getOpportunisticSubscriptions(mCallingPackage, mCallingFeature);
         assertEquals(1, opptSubList.size());
         assertEquals(2, opptSubList.get(0).getSubscriptionId());
         assertEquals(false, opptSubList.get(0).isGroupDisabled());
@@ -843,7 +906,8 @@
 
         verify(mTelephonyRegisteryMock, times(3))
                 .notifyOpportunisticSubscriptionInfoChanged();
-        opptSubList = mSubscriptionControllerUT.getOpportunisticSubscriptions(mCallingPackage);
+        opptSubList = mSubscriptionControllerUT.getOpportunisticSubscriptions(mCallingPackage,
+                mCallingFeature);
         assertEquals(1, opptSubList.size());
         assertEquals(2, opptSubList.get(0).getSubscriptionId());
         assertEquals(true, opptSubList.get(0).isGroupDisabled());
@@ -864,7 +928,7 @@
         assertTrue(mSubscriptionControllerUT.isActiveSubId(1));
         assertTrue(mSubscriptionControllerUT.isActiveSubId(2));
         assertTrue(TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, 1,
-                mContext.getOpPackageName(), "getSubscriptionsInGroup"));
+                mContext.getOpPackageName(), null, "getSubscriptionsInGroup"));
 
         int[] subIdList = new int[] {1};
         ParcelUuid groupUuid = mSubscriptionControllerUT.createSubscriptionGroup(
@@ -872,8 +936,8 @@
         assertNotEquals(null, groupUuid);
 
         // Sub 1 and sub 2 should be in same group.
-        List<SubscriptionInfo> infoList = mSubscriptionControllerUT
-                .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
+        List<SubscriptionInfo> infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(
+                groupUuid, mContext.getOpPackageName(), null);
         assertNotEquals(null, infoList);
         assertEquals(1, infoList.size());
         assertEquals(1, infoList.get(0).getSubscriptionId());
@@ -882,8 +946,8 @@
 
         mSubscriptionControllerUT.addSubscriptionsIntoGroup(
                 subIdList, groupUuid, mContext.getOpPackageName());
-        infoList = mSubscriptionControllerUT
-                .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
+        infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid,
+                mContext.getOpPackageName(), null);
         assertEquals(2, infoList.size());
         assertEquals(2, infoList.get(1).getSubscriptionId());
 
@@ -891,10 +955,19 @@
         subIdList = new int[] {1};
         mSubscriptionControllerUT.removeSubscriptionsFromGroup(
                 subIdList, groupUuid, mContext.getOpPackageName());
-        infoList = mSubscriptionControllerUT
-                .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
+        infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid,
+                mContext.getOpPackageName(), null);
         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(), null);
+        assertEquals(1, infoList.size());
+        assertEquals(1, infoList.get(0).getSubscriptionId());
     }
 
     private void registerMockTelephonyRegistry() {
@@ -995,15 +1068,27 @@
                 UiccSlotInfo.CARD_STATE_INFO_PRESENT, logicalSlotIndex, true, true);
     }
 
-    // TODO: Move this test once SubscriptionManager.setAlwaysAllowMmsData is moved to telephony
-    // manager.
     @Test
     @SmallTest
-    public void testSetAlwaysAllowMmsData() throws Exception {
-        mSubscriptionControllerUT.setAlwaysAllowMmsData(0, true);
-        verify(mDataEnabledSettings).setAlwaysAllowMmsData(eq(true));
-        clearInvocations(mDataEnabledSettings);
-        mSubscriptionControllerUT.setAlwaysAllowMmsData(0, false);
-        verify(mDataEnabledSettings).setAlwaysAllowMmsData(eq(false));
+    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));
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index 6c34903..e7a5303 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -232,6 +232,46 @@
 
     @Test
     @SmallTest
+    public void testSimNotReady() throws Exception {
+        mUpdater.updateInternalIccState(
+                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1, false);
+
+        processAllMessages();
+        assertFalse(mUpdater.isSubInfoInitialized());
+        verify(mSubscriptionContent, never()).put(anyString(), any());
+        CarrierConfigManager mConfigManager = (CarrierConfigManager)
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        verify(mConfigManager, never()).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+                eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
+        verify(mSubscriptionController, never()).clearSubInfo();
+        verify(mSubscriptionController, never()).notifySubscriptionInfoChanged();
+    }
+
+    @Test
+    @SmallTest
+    public void testSimNotReadyEmptyProfile() throws Exception {
+        doReturn(mIccCard).when(mPhone).getIccCard();
+        doReturn(true).when(mIccCard).isEmptyProfile();
+
+        mUpdater.updateInternalIccState(
+                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1, false);
+
+        processAllMessages();
+        assertTrue(mUpdater.isSubInfoInitialized());
+        // Sub info should be cleared and change should be notified.
+        verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_SUB_ID_1));
+        verify(mSubscriptionController).notifySubscriptionInfoChanged();
+        // No new sub should be added.
+        verify(mSubscriptionManager, never()).addSubscriptionInfoRecord(any(), anyInt());
+        verify(mSubscriptionContent, never()).put(anyString(), any());
+        CarrierConfigManager mConfigManager = (CarrierConfigManager)
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+                eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
+    }
+
+    @Test
+    @SmallTest
     public void testSimError() throws Exception {
         mUpdater.updateInternalIccState(
                 IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR, null, FAKE_SUB_ID_1, false);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionMonitorTest.java
deleted file mode 100644
index 215bb16..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionMonitorTest.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.content.Context;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.telephony.Rlog;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.internal.telephony.mocks.SubscriptionControllerMock;
-import com.android.internal.telephony.mocks.TelephonyRegistryMock;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-public class SubscriptionMonitorTest extends AndroidTestCase {
-    private final static String LOG_TAG = "SubscriptionMonitorTest";
-
-    static void failAndStack(String str) {
-        fail(str + "\n" + SubscriptionMonitorTest.stack());
-    }
-
-    static String stack() {
-        StringBuilder sb = new StringBuilder();
-        for(StackTraceElement e : Thread.currentThread().getStackTrace()) {
-            sb.append(e.toString()).append("\n");
-        }
-        return sb.toString();
-    }
-
-    private static class TestHandler extends Handler {
-        public final static int SUBSCRIPTION_CHANGED = 1;
-        public final static int IN_IDLE = 2;
-
-        HandlerThread handlerThread;
-
-        public TestHandler(Looper looper) {
-            super(looper);
-        }
-
-        public void die() {
-            if(handlerThread != null) {
-                handlerThread.quit();
-                handlerThread = null;
-            }
-        }
-
-        public void blockTilIdle() {
-            Object lock = new Object();
-            synchronized (lock) {
-                Message msg = this.obtainMessage(IN_IDLE, lock);
-                msg.sendToTarget();
-                try {
-                    lock.wait();
-                } catch (InterruptedException e) {}
-            }
-        }
-
-        public static TestHandler makeHandler() {
-            final HandlerThread handlerThread = new HandlerThread("TestHandler");
-            handlerThread.start();
-            final TestHandler result = new TestHandler(handlerThread.getLooper());
-            result.handlerThread = handlerThread;
-            return result;
-        }
-
-        private boolean objectEquals(Object o1, Object o2) {
-            if (o1 == null) return (o2 == null);
-            return o1.equals(o2);
-        }
-
-        private void failAndStack(String str) {
-            SubscriptionMonitorTest.failAndStack(str);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case SUBSCRIPTION_CHANGED: {
-                    AsyncResult ar = (AsyncResult)(msg.obj);
-                    if (objectEquals(ar.userObj, mSubscriptionChangedObject.get()) == false) {
-                        failAndStack("Subscription Changed object is incorrect!");
-                    }
-                    mSubscriptionChangedCount.incrementAndGet();
-                    Rlog.d(LOG_TAG, "SUBSCRIPTION_CHANGED, inc to " +
-                            mSubscriptionChangedCount.get());
-                    break;
-                }
-                case IN_IDLE: {
-                    Object lock = msg.obj;
-                    synchronized (lock) {
-                        lock.notify();
-                    }
-                    break;
-                }
-            }
-        }
-
-        private final AtomicInteger mSubscriptionChangedCount = new AtomicInteger(0);
-        private final AtomicReference<Object> mSubscriptionChangedObject =
-                new AtomicReference<Object>();
-
-        public void reset() {
-            mSubscriptionChangedCount.set(0);
-            mSubscriptionChangedObject.set(null);
-        }
-
-        public void setSubscriptionChangedObject(Object o) {
-            mSubscriptionChangedObject.set(o);
-        }
-
-        public int getSubscriptionChangedCount() {
-            return mSubscriptionChangedCount.get();
-        }
-    }
-
-    /**
-     * Register and unregister normally.
-     * Verify register worked by causing an event.
-     * Verify unregister by causing another event.
-     */
-    @SmallTest
-    public void testRegister() throws Exception {
-        final int numPhones = 2;
-        final ContextFixture contextFixture = new ContextFixture();
-        final Context context = contextFixture.getTestDouble();
-        ITelephonyRegistry.Stub telRegistry = new TelephonyRegistryMock();
-        SubscriptionControllerMock subController =
-                new SubscriptionControllerMock(context, telRegistry, numPhones);
-
-        SubscriptionMonitor testedSubMonitor =
-                new SubscriptionMonitor(telRegistry, context, subController, numPhones);
-
-        TestHandler testHandler = TestHandler.makeHandler();
-        Object subChangedObject = new Object();
-        testHandler.setSubscriptionChangedObject(subChangedObject);
-
-        // try events before registering
-        subController.setSlotSubId(0, 0);
-
-        if (testHandler.getSubscriptionChangedCount() != 0) {
-            fail("pretest of SubscriptionChangedCount");
-        }
-
-        testedSubMonitor.registerForSubscriptionChanged(0, testHandler,
-                  TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-        testHandler.blockTilIdle();
-
-        if (testHandler.getSubscriptionChangedCount() != 1) {
-            fail("test1 of SubscriptionChangedCount");
-        }
-
-        subController.setSlotSubId(0, 1);
-        testHandler.blockTilIdle();
-
-        if (testHandler.getSubscriptionChangedCount() != 2) {
-            fail("test2 of SubscriptionChangedCount");
-        }
-
-        subController.setSlotSubId(0, 0);
-        testHandler.blockTilIdle();
-
-        if (testHandler.getSubscriptionChangedCount() != 3) {
-            fail("test3 of SubscriptionChangedCount, " +
-                    testHandler.getSubscriptionChangedCount() + " vs 3");
-        }
-
-        testedSubMonitor.unregisterForSubscriptionChanged(0, testHandler);
-
-        subController.setSlotSubId(0, 1);
-        testHandler.blockTilIdle();
-
-        if (testHandler.getSubscriptionChangedCount() != 3) {
-            fail("test4 of SubscriptionChangedCount, " +
-                    testHandler.getSubscriptionChangedCount() + " vs 3");
-        }
-
-        testHandler.die();
-    }
-
-    /**
-     * Bad register/unregisters
-     *
-     * Try phoneId that doesn't exist.
-     * Cause an event and verify don't get notified.
-     * Try to unregister multiple times.
-     */
-    @SmallTest
-    public void testBadRegister() throws Exception {
-        final int numPhones = 2;
-        final ContextFixture contextFixture = new ContextFixture();
-        final Context context = contextFixture.getTestDouble();
-        ITelephonyRegistry.Stub telRegistry = new TelephonyRegistryMock();
-        SubscriptionControllerMock subController =
-                new SubscriptionControllerMock(context, telRegistry, numPhones);
-
-        SubscriptionMonitor testedSubMonitor =
-                new SubscriptionMonitor(telRegistry, context, subController, numPhones);
-
-        TestHandler testHandler = TestHandler.makeHandler();
-        Object subChangedObject = new Object();
-        testHandler.setSubscriptionChangedObject(subChangedObject);
-
-        try {
-            testedSubMonitor.registerForSubscriptionChanged(-1, testHandler,
-                      TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-            fail("IllegalArgumentException expected with bad phoneId");
-        } catch (IllegalArgumentException e) {}
-        try {
-            testedSubMonitor.registerForSubscriptionChanged(numPhones, testHandler,
-                      TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-            fail("IllegalArgumentException expected with bad phoneId");
-        } catch (IllegalArgumentException e) {}
-
-        subController.setSlotSubId(0, 0);
-
-        if (testHandler.getSubscriptionChangedCount() != 0) {
-            fail("getSubscriptionChangedCount reported non-zero!");
-        }
-
-        testHandler.die();
-    }
-
-    /**
-     * Try to force spurious notifications - register/unregister in tight loop with
-     * events happening in the unregistered gap.
-     */
-    @SmallTest
-    public void testSpuriousNotifications() throws Exception {
-        final int numPhones = 2;
-        final ContextFixture contextFixture = new ContextFixture();
-        final Context context = contextFixture.getTestDouble();
-        ITelephonyRegistry.Stub telRegistry = new TelephonyRegistryMock();
-        SubscriptionControllerMock subController =
-                new SubscriptionControllerMock(context, telRegistry, numPhones);
-
-        SubscriptionMonitor testedSubMonitor =
-                new SubscriptionMonitor(telRegistry, context, subController, numPhones);
-
-        TestHandler testHandler = TestHandler.makeHandler();
-        Object subChangedObject = new Object();
-        testHandler.setSubscriptionChangedObject(subChangedObject);
-
-        final int PHONE_ID = 0;
-        final int FIRST_SUB_ID = 0;
-        final int SECOND_SUB_ID = 1;
-
-        testedSubMonitor.registerForSubscriptionChanged(PHONE_ID, testHandler,
-                TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-        final int LOOP_COUNT = 1000;
-        for (int i = 0; i < LOOP_COUNT; i++) {
-            testedSubMonitor.unregisterForSubscriptionChanged(PHONE_ID, testHandler);
-
-            subController.setSlotSubId(PHONE_ID, FIRST_SUB_ID);
-            subController.setSlotSubId(PHONE_ID, SECOND_SUB_ID);
-
-            testedSubMonitor.registerForSubscriptionChanged(PHONE_ID, testHandler,
-                    TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-        }
-        testHandler.blockTilIdle();
-
-        // should get one for every registration
-        if (testHandler.getSubscriptionChangedCount() != 1 + LOOP_COUNT) {
-            fail("getSubscriptionChangedCount reported " +
-                    testHandler.getSubscriptionChangedCount() + " != " + (1 + LOOP_COUNT));
-        }
-
-        testHandler.die();
-    }
-
-    /**
-     * Test duplicate registrations - both should survive
-     * Also test duplicate unreg - shouldn't crash..
-     */
-    @SmallTest
-    public void testMultiRegUnregistration() throws Exception {
-        final int numPhones = 2;
-        final ContextFixture contextFixture = new ContextFixture();
-        final Context context = contextFixture.getTestDouble();
-        ITelephonyRegistry.Stub telRegistry = new TelephonyRegistryMock();
-        SubscriptionControllerMock subController =
-                new SubscriptionControllerMock(context, telRegistry, numPhones);
-
-        SubscriptionMonitor testedSubMonitor =
-                new SubscriptionMonitor(telRegistry, context, subController, numPhones);
-
-        TestHandler testHandler = TestHandler.makeHandler();
-        Object subChangedObject = new Object();
-        testHandler.setSubscriptionChangedObject(subChangedObject);
-
-        final int PHONE_ID = 0;
-        final int FIRST_SUB_ID = 0;
-        final int SECOND_SUB_ID = 1;
-
-        testedSubMonitor.registerForSubscriptionChanged(PHONE_ID, testHandler,
-                TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-        testedSubMonitor.registerForSubscriptionChanged(PHONE_ID, testHandler,
-                TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-
-        subController.setSlotSubId(PHONE_ID, FIRST_SUB_ID);
-        subController.setSlotSubId(PHONE_ID, SECOND_SUB_ID);
-
-        testHandler.blockTilIdle();
-
-        // should get 1 for each registration and 4 for the two events
-        if (testHandler.getSubscriptionChangedCount() != 6) {
-            fail("getSubscriptionChangedCount reported " +
-                    testHandler.getSubscriptionChangedCount() + " != 6");
-        }
-
-        testedSubMonitor.unregisterForSubscriptionChanged(PHONE_ID, testHandler);
-        testedSubMonitor.unregisterForSubscriptionChanged(PHONE_ID, testHandler);
-
-        testHandler.die();
-    }
-
-    /**
-     * Try event flood while registered - verify receive all.
-     */
-    @SmallTest
-    public void testEventFloodNotifications() throws Exception {
-        final int numPhones = 2;
-        final ContextFixture contextFixture = new ContextFixture();
-        final Context context = contextFixture.getTestDouble();
-        ITelephonyRegistry.Stub telRegistry = new TelephonyRegistryMock();
-        SubscriptionControllerMock subController =
-                new SubscriptionControllerMock(context, telRegistry, numPhones);
-
-        SubscriptionMonitor testedSubMonitor =
-                new SubscriptionMonitor(telRegistry, context, subController, numPhones);
-
-        TestHandler testHandler = TestHandler.makeHandler();
-        Object subChangedObject = new Object();
-        testHandler.setSubscriptionChangedObject(subChangedObject);
-
-        final int PHONE_ID = 0;
-        final int FIRST_SUB_ID = 0;
-        final int SECOND_SUB_ID = 1;
-
-        testedSubMonitor.registerForSubscriptionChanged(PHONE_ID, testHandler,
-                TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-
-        final int LOOP_COUNT = 1;
-        for (int i = 0; i < LOOP_COUNT; i++) {
-            subController.setSlotSubId(PHONE_ID, FIRST_SUB_ID);
-            subController.setSlotSubId(PHONE_ID, SECOND_SUB_ID);
-        }
-        testHandler.blockTilIdle();
-
-        // should get one for registration + 2 per loop
-        if (testHandler.getSubscriptionChangedCount() != 1 + (2 * LOOP_COUNT)) {
-            fail("getSubscriptionChangedCount reported " +
-                    testHandler.getSubscriptionChangedCount() + " != " + (1 + (2 * LOOP_COUNT)));
-        }
-
-        testHandler.die();
-    }
-
-    @SmallTest
-    public void testNoSubChange() throws Exception {
-        String TAG = "testNoSubChange";
-        final int numPhones = 2;
-        final ContextFixture contextFixture = new ContextFixture();
-        final Context context = contextFixture.getTestDouble();
-        ITelephonyRegistry.Stub telRegistry = new TelephonyRegistryMock();
-        SubscriptionControllerMock subController =
-                new SubscriptionControllerMock(context, telRegistry, numPhones);
-
-        SubscriptionMonitor testedSubMonitor =
-                new SubscriptionMonitor(telRegistry, context, subController, numPhones);
-
-        TestHandler testHandler = TestHandler.makeHandler();
-        Object subChangedObject = new Object();
-        testHandler.setSubscriptionChangedObject(subChangedObject);
-
-        final int PHONE_ID = 0;
-        final int FIRST_SUB_ID = 0;
-        final int SECOND_SUB_ID = 1;
-
-        testHandler.blockTilIdle();
-        Rlog.d(TAG, "1");
-
-        testedSubMonitor.registerForSubscriptionChanged(PHONE_ID, testHandler,
-                TestHandler.SUBSCRIPTION_CHANGED, subChangedObject);
-
-        testHandler.blockTilIdle();
-        Rlog.d(TAG, "2");
-
-        subController.setSlotSubId(PHONE_ID, FIRST_SUB_ID);
-
-        testHandler.blockTilIdle();
-        Rlog.d(TAG, "3");
-
-        if (testHandler.getSubscriptionChangedCount() != 2) {
-            fail("getSubscriptionChangedCount reported " +
-                    testHandler.getSubscriptionChangedCount() + " != 2");
-        }
-
-        Rlog.d(TAG, "4");
-
-        // cause a notification that subscription info changed
-        subController.notifySubscriptionInfoChanged();
-        testHandler.blockTilIdle();
-
-        Rlog.d(TAG, "5");
-
-        if (testHandler.getSubscriptionChangedCount() != 2) {
-            fail("getSubscriptionChangedCount reported " +
-                    testHandler.getSubscriptionChangedCount() + " != 2");
-        }
-
-        testHandler.die();
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
index f2d4a17..0fdeadc 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
@@ -18,11 +18,12 @@
 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.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.when;
@@ -32,8 +33,11 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ServiceManager;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
@@ -50,15 +54,17 @@
 import org.mockito.MockitoAnnotations;
 
 import java.lang.reflect.Field;
+import java.util.Map;
 
 @SmallTest
 public class TelephonyPermissionsTest {
 
     private static final int SUB_ID = 55555;
     private static final int SUB_ID_2 = 22222;
-    private static final int PID = 12345;
-    private static final int UID = 54321;
+    private static final int PID = Binder.getCallingPid();
+    private static final int UID = Binder.getCallingUid();
     private static final String PACKAGE = "com.example";
+    private static final String FEATURE = null;
     private static final String MSG = "message";
 
     @Mock
@@ -70,11 +76,19 @@
     @Mock
     private ITelephony mMockTelephony;
     @Mock
+    private IBinder mMockTelephonyBinder;
+    @Mock
     private PackageManager mMockPackageManager;
     @Mock
     private ApplicationInfo mMockApplicationInfo;
     @Mock
     private DevicePolicyManager mMockDevicePolicyManager;
+    @Mock
+    private TelephonyManager mTelephonyManagerMock;
+    @Mock
+    private TelephonyManager mTelephonyManagerMockForSub1;
+    @Mock
+    private TelephonyManager mTelephonyManagerMockForSub2;
 
     private MockContentResolver mMockContentResolver;
     private FakeSettingsConfigProvider mFakeSettingsConfigProvider;
@@ -82,6 +96,11 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+
+        when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(
+                mTelephonyManagerMock);
+        when(mTelephonyManagerMock.createForSubscriptionId(anyInt())).thenReturn(
+                mTelephonyManagerMock);
         when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOps);
         when(mMockContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)).thenReturn(
                 mMockSubscriptionManager);
@@ -101,17 +120,20 @@
                 AppOpsManager.MODE_ERRORED);
         when(mMockTelephony.getCarrierPrivilegeStatusForUid(eq(SUB_ID), eq(UID)))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+        when(mMockTelephony.getCarrierPrivilegeStatusForUid(eq(SUB_ID_2), eq(UID)))
+                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
         when(mMockContext.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
                 PID, UID)).thenReturn(PackageManager.PERMISSION_DENIED);
         when(mMockDevicePolicyManager.checkDeviceIdentifierAccess(eq(PACKAGE), eq(PID),
                 eq(UID))).thenReturn(false);
+        setTelephonyMockAsService();
     }
 
     @Test
     public void testCheckReadPhoneState_noPermissions() {
         try {
             TelephonyPermissions.checkReadPhoneState(
-                    mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG);
+                    mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG);
             fail("Should have thrown SecurityException");
         } catch (SecurityException e) {
             // expected
@@ -123,7 +145,7 @@
         doNothing().when(mMockContext).enforcePermission(
                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, PID, UID, MSG);
         assertTrue(TelephonyPermissions.checkReadPhoneState(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -133,7 +155,7 @@
         when(mMockAppOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, UID, PACKAGE))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         assertTrue(TelephonyPermissions.checkReadPhoneState(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -141,21 +163,23 @@
         doNothing().when(mMockContext).enforcePermission(
                 android.Manifest.permission.READ_PHONE_STATE, PID, UID, MSG);
         assertFalse(TelephonyPermissions.checkReadPhoneState(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
     public void testCheckReadPhoneState_hasCarrierPrivileges() throws Exception {
-        when(mMockTelephony.getCarrierPrivilegeStatusForUid(eq(SUB_ID), eq(UID)))
-                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID))).thenReturn(
+                mTelephonyManagerMockForSub1);
+        when(mTelephonyManagerMockForSub1.getCarrierPrivilegeStatus(anyInt())).thenReturn(
+                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         assertTrue(TelephonyPermissions.checkReadPhoneState(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
     public void testCheckReadPhoneStateOnAnyActiveSub_noPermissions() {
         assertFalse(TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
-                mMockContext, () -> mMockTelephony, PID, UID, PACKAGE, MSG));
+                mMockContext, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -163,7 +187,7 @@
         doNothing().when(mMockContext).enforcePermission(
                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, PID, UID, MSG);
         assertTrue(TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
-                mMockContext, () -> mMockTelephony, PID, UID, PACKAGE, MSG));
+                mMockContext, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -173,7 +197,7 @@
         when(mMockAppOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, UID, PACKAGE))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         assertTrue(TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
-                mMockContext, () -> mMockTelephony, PID, UID, PACKAGE, MSG));
+                mMockContext, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -181,22 +205,25 @@
         doNothing().when(mMockContext).enforcePermission(
                 android.Manifest.permission.READ_PHONE_STATE, PID, UID, MSG);
         assertFalse(TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
-                mMockContext, () -> mMockTelephony, PID, UID, PACKAGE, MSG));
+                mMockContext, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
     public void testCheckReadPhoneStateOnAnyActiveSub_hasCarrierPrivileges() throws Exception {
-        when(mMockTelephony.getCarrierPrivilegeStatusForUid(eq(SUB_ID), eq(UID)))
-                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID))).thenReturn(
+                mTelephonyManagerMockForSub1);
+        when(mTelephonyManagerMockForSub1.getCarrierPrivilegeStatus(anyInt())).thenReturn(
+                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         assertTrue(TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
-                mMockContext, () -> mMockTelephony, PID, UID, PACKAGE, MSG));
+                mMockContext, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
     public void testCheckReadPhoneNumber_noPermissions() {
         try {
             TelephonyPermissions.checkReadPhoneNumber(
-                    mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG);
+                    mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG);
             fail("Should have thrown SecurityException");
         } catch (SecurityException e) {
             // expected
@@ -208,7 +235,7 @@
         when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, UID, PACKAGE))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         assertTrue(TelephonyPermissions.checkReadPhoneNumber(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -216,7 +243,7 @@
         doNothing().when(mMockContext).enforcePermission(
                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, PID, UID, MSG);
         assertTrue(TelephonyPermissions.checkReadPhoneNumber(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -226,7 +253,7 @@
         when(mMockAppOps.noteOp(AppOpsManager.OPSTR_READ_SMS, UID, PACKAGE))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         assertTrue(TelephonyPermissions.checkReadPhoneNumber(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -236,15 +263,15 @@
         when(mMockAppOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, UID, PACKAGE))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         assertTrue(TelephonyPermissions.checkReadPhoneNumber(
-                mMockContext, () -> mMockTelephony, SUB_ID, PID, UID, PACKAGE, MSG));
+                mMockContext, SUB_ID, PID, UID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
     public void testCheckReadDeviceIdentifiers_noPermissions() throws Exception {
         setupMocksForDeviceIdentifiersErrorPath();
         try {
-            TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                    SUB_ID, PID, UID, PACKAGE, MSG);
+            TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                    SUB_ID, PACKAGE, FEATURE, MSG);
             fail("Should have thrown SecurityException");
         } catch (SecurityException e) {
             // expected
@@ -256,17 +283,19 @@
         when(mMockContext.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
                 PID, UID)).thenReturn(PackageManager.PERMISSION_GRANTED);
         assertTrue(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
     public void testCheckReadDeviceIdentifiers_hasCarrierPrivileges() throws Exception {
-        when(mMockTelephony.getCarrierPrivilegeStatusForUid(eq(SUB_ID), eq(UID)))
-                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID))).thenReturn(
+                mTelephonyManagerMockForSub1);
+        when(mTelephonyManagerMockForSub1.getCarrierPrivilegeStatus(anyInt())).thenReturn(
+                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         assertTrue(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -274,8 +303,8 @@
         when(mMockAppOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, UID,
                 PACKAGE)).thenReturn(AppOpsManager.MODE_ALLOWED);
         assertTrue(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -283,8 +312,8 @@
         when(mMockDevicePolicyManager.checkDeviceIdentifierAccess(eq(PACKAGE), eq(PID),
                 eq(UID))).thenReturn(true);
         assertTrue(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -296,8 +325,8 @@
                 UID)).thenReturn(PackageManager.PERMISSION_GRANTED);
         setupMocksForDeviceIdentifiersErrorPath();
         try {
-            TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                    SUB_ID, PID, UID, PACKAGE, MSG);
+            TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                    SUB_ID, PACKAGE, FEATURE, MSG);
             fail("Should have thrown SecurityException");
         } catch (SecurityException e) {
             // expected
@@ -314,8 +343,8 @@
         setupMocksForDeviceIdentifiersErrorPath();
         mMockApplicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
         assertFalse(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -323,11 +352,13 @@
             throws Exception {
         when(mMockSubscriptionManager.getActiveSubscriptionIdList(anyBoolean())).thenReturn(
                 new int[]{SUB_ID, SUB_ID_2});
-        when(mMockTelephony.getCarrierPrivilegeStatusForUid(eq(SUB_ID_2), eq(UID))).thenReturn(
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID_2))).thenReturn(
+                mTelephonyManagerMockForSub2);
+        when(mTelephonyManagerMockForSub2.getCarrierPrivilegeStatus(anyInt())).thenReturn(
                 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         assertTrue(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -337,11 +368,13 @@
                 new int[]{SUB_ID});
         when(mMockSubscriptionManager.getActiveSubscriptionIdList(false)).thenReturn(
                 new int[]{SUB_ID, SUB_ID_2});
-        when(mMockTelephony.getCarrierPrivilegeStatusForUid(eq(SUB_ID_2), eq(UID)))
-                .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID_2))).thenReturn(
+                mTelephonyManagerMockForSub2);
+        when(mTelephonyManagerMockForSub2.getCarrierPrivilegeStatus(anyInt())).thenReturn(
+                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
         assertTrue(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID_2, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -354,8 +387,8 @@
         when(mMockAppOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, UID,
                 PACKAGE)).thenReturn(AppOpsManager.MODE_ALLOWED);
         assertTrue(
-                TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                        SUB_ID, PID, UID, PACKAGE, MSG));
+                TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
     }
 
     @Test
@@ -365,14 +398,177 @@
         // case.
         setupMocksForDeviceIdentifiersErrorPath();
         try {
-            TelephonyPermissions.checkReadDeviceIdentifiers(mMockContext, () -> mMockTelephony,
-                    SUB_ID, PID, UID, null, MSG);
+            TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
+                    SUB_ID, null, FEATURE, MSG);
             fail("Should have thrown SecurityException");
         } catch (SecurityException e) {
             // expected
         }
     }
 
+    @Test
+    public void testCheckCallingOrSelfReadSubscriberIdentifiers_noPermissions() throws Exception {
+        setupMocksForDeviceIdentifiersErrorPath();
+        setTelephonyMockAsService();
+        when(mMockContext.checkPermission(
+                eq(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE),
+                anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
+        when(mMockAppOps.noteOpNoThrow(anyString(), anyInt(), eq(PACKAGE))).thenReturn(
+                AppOpsManager.MODE_ERRORED);
+        when(mMockDevicePolicyManager.checkDeviceIdentifierAccess(eq(PACKAGE), anyInt(),
+                anyInt())).thenReturn(false);
+        try {
+            TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(mMockContext,
+                    SUB_ID, PACKAGE, FEATURE, MSG);
+            fail("Should have thrown SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testCheckCallingOrSelfReadSubscriberIdentifiers_carrierPrivileges()
+            throws Exception {
+        setTelephonyMockAsService();
+        when(mMockContext.checkPermission(
+                eq(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE),
+                anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID))).thenReturn(
+                mTelephonyManagerMockForSub1);
+        when(mTelephonyManagerMockForSub1.getCarrierPrivilegeStatus(anyInt())).thenReturn(
+                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        assertTrue(
+                TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(mMockContext,
+                        SUB_ID, PACKAGE, FEATURE, MSG));
+    }
+
+    @Test
+    public void testCheckCallingOrSelfReadSubscriberIdentifiers_carrierPrivilegesOnOtherSub()
+            throws Exception {
+        setupMocksForDeviceIdentifiersErrorPath();
+        setTelephonyMockAsService();
+        when(mMockContext.checkPermission(
+                eq(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE),
+                anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
+        when(mMockSubscriptionManager.getActiveSubscriptionIdList(anyBoolean())).thenReturn(
+                new int[]{SUB_ID, SUB_ID_2});
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID_2))).thenReturn(
+                mTelephonyManagerMockForSub2);
+        when(mTelephonyManagerMockForSub2.getCarrierPrivilegeStatus(anyInt())).thenReturn(
+                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        // Carrier privilege on the other active sub shouldn't allow access to this sub.
+        try {
+            TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(mMockContext,
+                    SUB_ID, PACKAGE, FEATURE, MSG);
+            fail("Should have thrown SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Validate the SecurityException will be thrown if call the method without permissions, nor
+     * privileges.
+     */
+    @Test
+    public void
+    testEnforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege_noPermissions()
+            throws Exception {
+        // revoke permission READ_PRIVILEGED_PHONE_STATE
+        when(mMockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+        // revoke permision READ_PRECISE_PHONE_STATE
+        when(mMockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRECISE_PHONE_STATE)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+        try {
+            TelephonyPermissions
+                    .enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                    mMockContext, SUB_ID, MSG);
+            fail("Should have thrown SecurityException");
+        } catch (SecurityException se) {
+            // expected
+        }
+    }
+
+    /**
+     * Validate that no SecurityException thrown when we have either permission
+     * READ_PRECISE_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE.
+     */
+    @Test
+    public void
+    testEnforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege_withPermissions()
+            throws Exception {
+        // grant READ_PRIVILEGED_PHONE_STATE permission
+        when(mMockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+        try {
+            TelephonyPermissions
+                    .enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                    mMockContext, SUB_ID, MSG);
+        } catch (SecurityException se) {
+            fail();
+        }
+
+        // revoke permission READ_PRIVILEGED_PHONE_STATE
+        when(mMockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        // grant READ_PRECISE_PHONE_STATE permission
+        when(mMockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRECISE_PHONE_STATE)).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+        try {
+            TelephonyPermissions
+                    .enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                    mMockContext, SUB_ID, MSG);
+        } catch (SecurityException se) {
+            fail();
+        }
+    }
+
+    /**
+     * Validate that no SecurityException thrown when we have carrier privileges.
+     */
+    @Test
+    public void
+    testEnforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege_withPrivileges()
+            throws Exception {
+        // revoke permission READ_PRIVILEGED_PHONE_STATE
+        when(mMockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+        // revoke permision READ_PRECISE_PHONE_STATE
+        when(mMockContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRECISE_PHONE_STATE)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        setTelephonyMockAsService();
+        when(mTelephonyManagerMock.createForSubscriptionId(eq(SUB_ID))).thenReturn(
+                mTelephonyManagerMockForSub1);
+        when(mTelephonyManagerMockForSub1.getCarrierPrivilegeStatus(anyInt())).thenReturn(
+                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+        try {
+            TelephonyPermissions
+                    .enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                    mMockContext, SUB_ID, MSG);
+        } catch (SecurityException se) {
+            fail("Should NOT throw SecurityException");
+        }
+    }
+
+    // Put mMockTelephony into service cache so that TELEPHONY_SUPPLIER will get it.
+    private void setTelephonyMockAsService() throws Exception {
+        when(mMockTelephonyBinder.queryLocalInterface(anyString())).thenReturn(mMockTelephony);
+        Field field = ServiceManager.class.getDeclaredField("sCache");
+        field.setAccessible(true);
+        ((Map<String, IBinder>) field.get(null)).put(Context.TELEPHONY_SERVICE,
+                mMockTelephonyBinder);
+    }
+
     public static class FakeSettingsConfigProvider extends FakeSettingsProvider {
         private static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED =
                 DeviceConfig.NAMESPACE_PRIVACY + "/"
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
index 7aa1ff1..881d454 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
@@ -17,7 +17,13 @@
 
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
 import static android.telephony.PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE;
+import static android.telephony.PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED;
 import static android.telephony.PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED;
+import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
+import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
+import static android.telephony.TelephonyManager.RADIO_POWER_OFF;
+import static android.telephony.TelephonyManager.RADIO_POWER_ON;
+import static android.telephony.TelephonyManager.RADIO_POWER_UNAVAILABLE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
@@ -25,9 +31,14 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
+import android.content.Intent;
+import android.net.LinkProperties;
 import android.os.ServiceManager;
+import android.telephony.Annotation;
 import android.telephony.PhoneCapability;
 import android.telephony.PhoneStateListener;
+import android.telephony.PreciseDataConnectionState;
+import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -41,43 +52,103 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class TelephonyRegistryTest extends TelephonyTest {
     @Mock
-    private ISub.Stub mISubStub;
-    private PhoneStateListener mPhoneStateListener;
+    private SubscriptionInfo mMockSubInfo;
+    private PhoneStateListenerWrapper mPhoneStateListener;
     private TelephonyRegistry mTelephonyRegistry;
     private PhoneCapability mPhoneCapability;
     private int mActiveSubId;
     private int mSrvccState = -1;
+    private int mRadioPowerState = RADIO_POWER_UNAVAILABLE;
+    // All events contribute to TelephonyRegistry.ENFORCE_PHONE_STATE_PERMISSION_MASK
+    private static final Map<Integer, String> READ_PHONE_STATE_EVENTS = Map.of(
+            PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR,
+            "PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR",
+            PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR,
+            "PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR",
+            PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST,
+            "PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST",
+            PhoneStateListener.LISTEN_REGISTRATION_FAILURE,
+            "PhoneStateListener.LISTEN_REGISTRATION_FAILURE");
+
+    // All events contribute to TelephonyRegistry.PRECISE_PHONE_STATE_PERMISSION_MASK
+    private static final Map<Integer, String> READ_PRECISE_PHONE_STATE_EVENTS = Map.of(
+            PhoneStateListener.LISTEN_PRECISE_CALL_STATE,
+            "PhoneStateListener.LISTEN_PRECISE_CALL_STATE",
+            PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE,
+            "PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE",
+            PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES,
+            "PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES",
+            PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED,
+            "PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED",
+            PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES,
+            "PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES");
+
+    // All events contribute to TelephonyRegistry.PREVILEGED_PHONE_STATE_PERMISSION_MASK
+    // TODO: b/148021947 will create the permission group with PREVILIGED_STATE_PERMISSION_MASK
+    private static final Map<Integer, String> READ_PREVILIGED_PHONE_STATE_EVENTS = Map.of(
+            PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED,
+            "PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED",
+            PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT,
+            "PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT",
+            PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED,
+            "PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED",
+            PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE,
+            "PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE");
+
+    // All events contribute to TelephonyRegistry.READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK
+    private static final Map<Integer, String> READ_ACTIVE_EMERGENCY_SESSION_EVENTS = Map.of(
+            PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL,
+            "PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL",
+            PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS,
+            "PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS");
 
     public class PhoneStateListenerWrapper extends PhoneStateListener {
+        // This class isn't mockable to get invocation counts because the IBinder is null and
+        // crashes the TelephonyRegistry. Make a cheesy verify(times()) alternative.
+        public AtomicInteger invocationCount = new AtomicInteger(0);
+
         @Override
         public void onSrvccStateChanged(int srvccState) {
+            invocationCount.incrementAndGet();
             mSrvccState = srvccState;
         }
 
         @Override
         public void onPhoneCapabilityChanged(PhoneCapability capability) {
+            invocationCount.incrementAndGet();
             mPhoneCapability = capability;
         }
         @Override
         public void onActiveDataSubscriptionIdChanged(int activeSubId) {
+            invocationCount.incrementAndGet();
             mActiveSubId = activeSubId;
         }
+        @Override
+        public void onRadioPowerStateChanged(@Annotation.RadioPowerState int state) {
+            invocationCount.incrementAndGet();
+            mRadioPowerState = state;
+        }
+        @Override
+        public void onPreciseDataConnectionStateChanged(PreciseDataConnectionState preciseState) {
+            invocationCount.incrementAndGet();
+        }
     }
 
     private void addTelephonyRegistryService() {
         mServiceManagerMockedServices.put("telephony.registry", mTelephonyRegistry.asBinder());
+        mTelephonyRegistry.systemRunning();
     }
 
     @Before
     public void setUp() throws Exception {
         super.setUp("TelephonyRegistryTest");
-        // ServiceManager.getService("isub") will return this stub for any call to
-        // SubscriptionManager.
-        mServiceManagerMockedServices.put("isub", mISubStub);
         mTelephonyRegistry = new TelephonyRegistry(mContext);
         addTelephonyRegistryService();
         mPhoneStateListener = new PhoneStateListenerWrapper();
@@ -94,17 +165,20 @@
 
     @Test @SmallTest
     public void testPhoneCapabilityChanged() {
+        doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
+        doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex();
         // mTelephonyRegistry.listen with notifyNow = true should trigger callback immediately.
-        PhoneCapability phoneCapability = new PhoneCapability(1, 2, 3, null, false);
+        PhoneCapability phoneCapability = new PhoneCapability(1, 2, 3, 4, 5, 6,
+                null, null, null, null, null, null, null);
         mTelephonyRegistry.notifyPhoneCapabilityChanged(phoneCapability);
-        mTelephonyRegistry.listen(mContext.getOpPackageName(),
-                mPhoneStateListener.callback,
-                LISTEN_PHONE_CAPABILITY_CHANGE, true);
+        mTelephonyRegistry.listenWithFeature(mContext.getOpPackageName(), null,
+                mPhoneStateListener.callback, LISTEN_PHONE_CAPABILITY_CHANGE, true);
         processAllMessages();
         assertEquals(phoneCapability, mPhoneCapability);
 
         // notifyPhoneCapabilityChanged with a new capability. Callback should be triggered.
-        phoneCapability = new PhoneCapability(3, 2, 2, null, false);
+        phoneCapability = new PhoneCapability(6, 5, 4, 3, 2, 1,
+                null, null, null, null, null, null, null);
         mTelephonyRegistry.notifyPhoneCapabilityChanged(phoneCapability);
         processAllMessages();
         assertEquals(phoneCapability, mPhoneCapability);
@@ -118,7 +192,7 @@
         when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(activeSubs);
         int activeSubId = 0;
         mTelephonyRegistry.notifyActiveDataSubIdChanged(activeSubId);
-        mTelephonyRegistry.listen(mContext.getOpPackageName(),
+        mTelephonyRegistry.listenWithFeature(mContext.getOpPackageName(), null,
                 mPhoneStateListener.callback,
                 LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE, true);
         processAllMessages();
@@ -139,20 +213,21 @@
     @Test
     @SmallTest
     public void testSrvccStateChanged() throws Exception {
-        // Return a phone ID of 0 for all sub ids given.
-        doReturn(0/*phoneId*/).when(mISubStub).getPhoneId(anyInt());
+        // Return a slotIndex / phoneId of 0 for all sub ids given.
+        doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
+        doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex();
         int srvccState = TelephonyManager.SRVCC_STATE_HANDOVER_STARTED;
-        mTelephonyRegistry.notifySrvccStateChanged(0 /*subId*/, srvccState);
+        mTelephonyRegistry.notifySrvccStateChanged(1 /*subId*/, srvccState);
         // Should receive callback when listen is called that contains the latest notify result.
-        mTelephonyRegistry.listenForSubscriber(0 /*subId*/, mContext.getOpPackageName(),
-                mPhoneStateListener.callback,
+        mTelephonyRegistry.listenForSubscriber(1 /*subId*/, mContext.getOpPackageName(),
+                null, mPhoneStateListener.callback,
                 LISTEN_SRVCC_STATE_CHANGED, true);
         processAllMessages();
         assertEquals(srvccState, mSrvccState);
 
         // trigger callback
         srvccState = TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED;
-        mTelephonyRegistry.notifySrvccStateChanged(0 /*subId*/, srvccState);
+        mTelephonyRegistry.notifySrvccStateChanged(1 /*subId*/, srvccState);
         processAllMessages();
         assertEquals(srvccState, mSrvccState);
     }
@@ -170,11 +245,187 @@
         mTelephonyRegistry.notifySrvccStateChanged(0 /*subId*/, srvccState);
         try {
             mTelephonyRegistry.listenForSubscriber(0 /*subId*/, mContext.getOpPackageName(),
-                    mPhoneStateListener.callback,
+                    null, mPhoneStateListener.callback,
                     LISTEN_SRVCC_STATE_CHANGED, true);
             fail();
         } catch (SecurityException e) {
             // pass test!
         }
     }
+
+    /**
+     * Test multi sim config change.
+     */
+    @Test
+    public void testMultiSimConfigChange() {
+        mTelephonyRegistry.listenForSubscriber(1, mContext.getOpPackageName(),
+                null, mPhoneStateListener.callback,
+                LISTEN_RADIO_POWER_STATE_CHANGED, true);
+        processAllMessages();
+        assertEquals(RADIO_POWER_UNAVAILABLE, mRadioPowerState);
+
+        // Notify RADIO_POWER_ON on invalid phoneId. Shouldn't go through.
+        mTelephonyRegistry.notifyRadioPowerStateChanged(1, 1, RADIO_POWER_ON);
+        processAllMessages();
+        assertEquals(RADIO_POWER_UNAVAILABLE, mRadioPowerState);
+
+        // Switch to DSDS and re-send RADIO_POWER_ON on phone 1. This time it should be notified.
+        doReturn(MODEM_COUNT_DUAL_MODEM).when(mTelephonyManager).getActiveModemCount();
+        mContext.sendBroadcast(new Intent(ACTION_MULTI_SIM_CONFIG_CHANGED));
+        mTelephonyRegistry.notifyRadioPowerStateChanged(1, 1, RADIO_POWER_ON);
+        processAllMessages();
+        assertEquals(RADIO_POWER_ON, mRadioPowerState);
+
+        // Switch back to single SIM mode and re-send on phone 0. This time it should be notified.
+        doReturn(MODEM_COUNT_DUAL_MODEM).when(mTelephonyManager).getActiveModemCount();
+        mContext.sendBroadcast(new Intent(ACTION_MULTI_SIM_CONFIG_CHANGED));
+        mTelephonyRegistry.notifyRadioPowerStateChanged(0, 1, RADIO_POWER_OFF);
+        processAllMessages();
+        assertEquals(RADIO_POWER_OFF, mRadioPowerState);
+    }
+
+    /**
+     * Test multi sim config change.
+     */
+    @Test
+    public void testPreciseDataConnectionStateChanged() {
+        final int subId = 1;
+        doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
+        doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex();
+        // Initialize the PSL with a PreciseDataConnection
+        mTelephonyRegistry.notifyDataConnectionForSubscriber(
+                /*phoneId*/ 0, subId, "default",
+                new PreciseDataConnectionState(
+                    0, 0, 0, "default", new LinkProperties(), 0, null));
+        mTelephonyRegistry.listenForSubscriber(subId, mContext.getOpPackageName(),
+                null, mPhoneStateListener.callback,
+                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE, true);
+        processAllMessages();
+        // Verify that the PDCS is reported for the only APN
+        assertEquals(mPhoneStateListener.invocationCount.get(), 1);
+
+        // Add IMS APN and verify that the listener is invoked for the IMS APN
+        mTelephonyRegistry.notifyDataConnectionForSubscriber(
+                /*phoneId*/ 0, subId, "ims",
+                new PreciseDataConnectionState(
+                    0, 0, 0, "ims", new LinkProperties(), 0, null));
+        processAllMessages();
+
+        assertEquals(mPhoneStateListener.invocationCount.get(), 2);
+
+        // Unregister the listener
+        mTelephonyRegistry.listenForSubscriber(subId, mContext.getOpPackageName(),
+                null, mPhoneStateListener.callback,
+                PhoneStateListener.LISTEN_NONE, true);
+        processAllMessages();
+
+        // Re-register the listener and ensure that both APN types are reported
+        mTelephonyRegistry.listenForSubscriber(subId, mContext.getOpPackageName(),
+                null, mPhoneStateListener.callback,
+                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE, true);
+        processAllMessages();
+        assertEquals(mPhoneStateListener.invocationCount.get(), 4);
+
+        // Send a duplicate event to the TelephonyRegistry and verify that the listener isn't
+        // invoked.
+        mTelephonyRegistry.notifyDataConnectionForSubscriber(
+                /*phoneId*/ 0, subId, "ims",
+                new PreciseDataConnectionState(
+                    0, 0, 0, "ims", new LinkProperties(), 0, null));
+        processAllMessages();
+        assertEquals(mPhoneStateListener.invocationCount.get(), 4);
+    }
+
+    /**
+     * Test listen to events that require READ_PHONE_STATE permission.
+     */
+    @Test
+    public void testReadPhoneStatePermission() {
+        // Clear all permission grants for test.
+        mContextFixture.addCallingOrSelfPermission("");
+        for (Map.Entry<Integer, String> entry : READ_PHONE_STATE_EVENTS.entrySet()) {
+            assertSecurityExceptionThrown(entry.getKey(), entry.getValue());
+        }
+
+        // Grant permssion
+        mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
+        for (Map.Entry<Integer, String> entry : READ_PHONE_STATE_EVENTS.entrySet()) {
+            assertSecurityExceptionNotThrown(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Test listen to events that require READ_PRECISE_PHONE_STATE permission.
+     */
+    @Test
+    public void testReadPrecisePhoneStatePermission() {
+        // Clear all permission grants for test.
+        mContextFixture.addCallingOrSelfPermission("");
+        for (Map.Entry<Integer, String> entry : READ_PRECISE_PHONE_STATE_EVENTS.entrySet()) {
+            assertSecurityExceptionThrown(entry.getKey(), entry.getValue());
+        }
+
+        // Grant permssion
+        mContextFixture.addCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
+        for (Map.Entry<Integer, String> entry : READ_PRECISE_PHONE_STATE_EVENTS.entrySet()) {
+            assertSecurityExceptionNotThrown(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Test listen to events that require READ_PRIVILEGED_PHONE_STATE permission.
+     */
+    @Test
+    public void testReadPrivilegedPhoneStatePermission() {
+        // Clear all permission grants for test.
+        mContextFixture.addCallingOrSelfPermission("");
+        for (Map.Entry<Integer, String> entry : READ_PREVILIGED_PHONE_STATE_EVENTS.entrySet()) {
+            assertSecurityExceptionThrown(entry.getKey(), entry.getValue());
+        }
+
+        // Grant permssion
+        mContextFixture.addCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+        for (Map.Entry<Integer, String> entry : READ_PREVILIGED_PHONE_STATE_EVENTS.entrySet()) {
+            assertSecurityExceptionNotThrown(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Test listen to events that require READ_ACTIVE_EMERGENCY_SESSION permission.
+     */
+    @Test
+    public void testReadActiveEmergencySessionPermission() {
+        // Clear all permission grants for test.
+        mContextFixture.addCallingOrSelfPermission("");
+        for (Map.Entry<Integer, String> entry : READ_ACTIVE_EMERGENCY_SESSION_EVENTS.entrySet()) {
+            assertSecurityExceptionThrown(entry.getKey(), entry.getValue());
+        }
+
+        // Grant permssion
+        mContextFixture.addCallingOrSelfPermission(
+                android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION);
+        for (Map.Entry<Integer, String> entry : READ_ACTIVE_EMERGENCY_SESSION_EVENTS.entrySet()) {
+            assertSecurityExceptionNotThrown(entry.getKey(), entry.getValue());
+        }
+    }
+
+    private void assertSecurityExceptionThrown(int event, String eventDesc) {
+        try {
+            mTelephonyRegistry.listen(mContext.getOpPackageName(),
+                    mPhoneStateListener.callback, event, true);
+            fail("SecurityException should throw when listen " + eventDesc + " without permission");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    private void assertSecurityExceptionNotThrown(int event, String eventDesc) {
+        try {
+            mTelephonyRegistry.listen(mContext.getOpPackageName(),
+                    mPhoneStateListener.callback, event, true);
+        } catch (SecurityException unexpected) {
+            fail("SecurityException thrown when listen " + eventDesc + " with permission");
+        }
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 1c05743..d3115fe 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -49,7 +49,6 @@
 import android.os.MessageQueue;
 import android.os.RegistrantList;
 import android.os.ServiceManager;
-import android.os.telephony.TelephonyRegistryManager;
 import android.provider.BlockedNumberContract;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
@@ -58,6 +57,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsCallProfile;
@@ -268,6 +268,8 @@
     protected UiccCard mUiccCard;
     @Mock
     protected MultiSimSettingController mMultiSimSettingController;
+    @Mock
+    protected IccCard mIccCard;
 
     protected ImsCallProfile mImsCallProfile;
     protected TelephonyManager mTelephonyManager;
@@ -620,6 +622,8 @@
         replaceInstance(MultiSimSettingController.class, "sInstance", null,
                 mMultiSimSettingController);
         replaceInstance(SubscriptionInfoUpdater.class, "sIsSubInfoInitialized", null, true);
+        replaceInstance(PhoneFactory.class, "sCommandsInterfaces", null,
+                new CommandsInterface[] {mSimulatedCommands});
 
         assertNotNull("Failed to set up SubscriptionController singleton",
                 SubscriptionController.getInstance());
@@ -659,14 +663,14 @@
         @Override
         public Bundle call(String method, String arg, Bundle extras) {
             switch (method) {
-                case BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER:
+                case BlockedNumberContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER:
                     Bundle bundle = new Bundle();
                     int blockStatus = mBlockedNumbers.contains(arg)
                             ? BlockedNumberContract.STATUS_BLOCKED_IN_LIST
                             : BlockedNumberContract.STATUS_NOT_BLOCKED;
                     bundle.putInt(BlockedNumberContract.RES_BLOCK_STATUS, blockStatus);
                     return bundle;
-                case BlockedNumberContract.SystemContract.METHOD_NOTIFY_EMERGENCY_CONTACT:
+                case BlockedNumberContract.METHOD_NOTIFY_EMERGENCY_CONTACT:
                     mNumEmergencyContactNotifications++;
                     return new Bundle();
                 default:
@@ -709,8 +713,6 @@
     protected void setupMockPackagePermissionChecks() throws Exception {
         doReturn(new String[]{TAG}).when(mPackageManager).getPackagesForUid(anyInt());
         doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(eq(TAG), anyInt());
-        doReturn(mPackageInfo).when(mPackageManager).getPackageInfoAsUser(
-                eq(TAG), anyInt(), anyInt());
     }
 
     protected void setupMocksForTelephonyPermissions() throws Exception {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TimeZoneLookupHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/TimeZoneLookupHelperTest.java
index 2a1befb..1d00bac 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TimeZoneLookupHelperTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TimeZoneLookupHelperTest.java
@@ -29,9 +29,9 @@
 
 import android.icu.util.GregorianCalendar;
 import android.icu.util.TimeZone;
+import android.timezone.CountryTimeZones.OffsetResult;
 
 import com.android.internal.telephony.TimeZoneLookupHelper.CountryResult;
-import com.android.internal.telephony.TimeZoneLookupHelper.OffsetResult;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -161,7 +161,7 @@
             // The zone chosen is a side effect of zone ordering in the data files so we just check
             // the isOnlyMatch value.
             OffsetResult offsetResult = mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, usIso);
-            assertFalse(offsetResult.getIsOnlyMatch());
+            assertFalse(offsetResult.isOnlyMatch());
         }
 
         // Try MDT / -6 hours in summer after America/North_Dakota/Beulah switched to central time.
@@ -169,7 +169,7 @@
             String nitzString = "11/11/05,00:00:00-24,1"; // 2011-11-05 00:00:00 UTC, UTC-6, DST
             NitzData nitzData = NitzData.parse(nitzString);
             OffsetResult offsetResult = mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, usIso);
-            assertTrue(offsetResult.getIsOnlyMatch());
+            assertTrue(offsetResult.isOnlyMatch());
         }
     }
 
@@ -184,7 +184,7 @@
             String nitzString = "15/06/01,00:00:00-24,1"; // 2015-06-01 00:00:00 UTC, UTC-6, DST
             NitzData nitzData = NitzData.parse(nitzString);
             OffsetResult offsetResult = mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, usIso);
-            assertTrue(offsetResult.getIsOnlyMatch());
+            assertTrue(offsetResult.isOnlyMatch());
         }
 
         // Try MST for a recent summer date: No ambiguity here.
@@ -192,7 +192,7 @@
             String nitzString = "15/06/01,00:00:00-28,0"; // 2015-06-01 00:00:00 UTC, UTC-7, not DST
             NitzData nitzData = NitzData.parse(nitzString);
             OffsetResult offsetResult = mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, usIso);
-            assertTrue(offsetResult.getIsOnlyMatch());
+            assertTrue(offsetResult.isOnlyMatch());
         }
 
         // Try MST for a recent winter date: There are multiple zones to pick from because of the
@@ -201,7 +201,7 @@
             String nitzString = "15/01/01,00:00:00-28,0"; // 2015-01-01 00:00:00 UTC, UTC-7, not DST
             NitzData nitzData = NitzData.parse(nitzString);
             OffsetResult offsetResult = mTimeZoneLookupHelper.lookupByNitzCountry(nitzData, usIso);
-            assertFalse(offsetResult.getIsOnlyMatch());
+            assertFalse(offsetResult.isOnlyMatch());
         }
     }
 
@@ -376,7 +376,7 @@
         OffsetResult majorityOffsetResult =
                 mTimeZoneLookupHelper.lookupByNitzCountry(majorityNitzData, countryIsoCode);
         assertEquals(zone("Pacific/Auckland"), majorityOffsetResult.getTimeZone());
-        assertTrue(majorityOffsetResult.getIsOnlyMatch());
+        assertTrue(majorityOffsetResult.isOnlyMatch());
 
         // Data correct for the Chatham Islands.
         int chathamWinterOffset = majorityWinterOffset + ((int) TimeUnit.MINUTES.toMillis(45));
@@ -385,7 +385,7 @@
         OffsetResult chathamOffsetResult =
                 mTimeZoneLookupHelper.lookupByNitzCountry(chathamNitzData, countryIsoCode);
         assertEquals(zone("Pacific/Chatham"), chathamOffsetResult.getTimeZone());
-        assertTrue(chathamOffsetResult.getIsOnlyMatch());
+        assertTrue(chathamOffsetResult.isOnlyMatch());
 
         // NITZ data that makes no sense for NZ results in no match.
         int nonsenseOffset = (int) TimeUnit.HOURS.toMillis(5);
@@ -416,7 +416,7 @@
         OffsetResult chuukOffsetResult =
                 mTimeZoneLookupHelper.lookupByNitzCountry(chuukNitzData, countryIsoCode);
         assertEquals(zone("Pacific/Chuuk"), chuukOffsetResult.getTimeZone());
-        assertTrue(chuukOffsetResult.getIsOnlyMatch());
+        assertTrue(chuukOffsetResult.isOnlyMatch());
 
         // NITZ data that makes no sense for FM: no boost means we should get nothing.
         int nonsenseOffset = (int) TimeUnit.HOURS.toMillis(5);
@@ -470,7 +470,7 @@
     }
 
     private static void assertOffsetResultMetadata(boolean isOnlyMatch, OffsetResult lookupResult) {
-        assertEquals(isOnlyMatch, lookupResult.getIsOnlyMatch());
+        assertEquals(isOnlyMatch, lookupResult.isOnlyMatch());
     }
 
     private static long createUtcTime(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/WapPushOverSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/WapPushOverSmsTest.java
index 284a859..911523b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/WapPushOverSmsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/WapPushOverSmsTest.java
@@ -45,7 +45,7 @@
 
 public class WapPushOverSmsTest extends TelephonyTest {
     @Mock
-    protected IMms.Stub mIMmsStub;
+    protected ISms.Stub mISmsStub;
 
     private WapPushOverSms mWapPushOverSmsUT;
 
@@ -55,8 +55,8 @@
 
         // Note that this replaces only cached services in ServiceManager. If a service is not found
         // in the cache, a real instance is used.
-        mServiceManagerMockedServices.put("imms", mIMmsStub);
-        doReturn(mIMmsStub).when(mIMmsStub).queryLocalInterface(anyString());
+        mServiceManagerMockedServices.put("isms", mISmsStub);
+        doReturn(mISmsStub).when(mISmsStub).queryLocalInterface(anyString());
 
         mWapPushOverSmsUT = new WapPushOverSms(mContext);
     }
@@ -89,7 +89,7 @@
         ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mInboundSmsHandler).dispatchIntent(intentArgumentCaptor.capture(),
                 eq(android.Manifest.permission.RECEIVE_WAP_PUSH),
-                eq(AppOpsManager.OP_RECEIVE_WAP_PUSH),
+                eq(AppOpsManager.OPSTR_RECEIVE_WAP_PUSH),
                 nullable(Bundle.class),
                 isNull(BroadcastReceiver.class),
                 eq(UserHandle.SYSTEM),
@@ -118,7 +118,7 @@
 
     @Test @SmallTest
     public void testDispatchWapPduFromBlockedNumber_noIntentsDispatched() throws Exception {
-        when(mIMmsStub.getCarrierConfigValues(anyInt())).thenReturn(new Bundle());
+        when(mISmsStub.getCarrierConfigValuesForSubscriber(anyInt())).thenReturn(new Bundle());
 
         mFakeBlockedNumberContentProvider.mBlockedNumbers.add("16178269168");
 
@@ -143,7 +143,7 @@
         verify(mInboundSmsHandler, never()).dispatchIntent(
                 any(Intent.class),
                 any(String.class),
-                anyInt(),
+                any(String.class),
                 any(Bundle.class),
                 any(BroadcastReceiver.class),
                 any(UserHandle.class),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
index 46af98f..3d707da 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
@@ -17,7 +17,6 @@
 package com.android.internal.telephony.cdma;
 
 import android.hardware.radio.V1_0.CdmaSmsMessage;
-import android.telephony.Rlog;
 import android.telephony.SmsCbCmasInfo;
 import android.telephony.SmsCbMessage;
 import android.telephony.cdma.CdmaSmsCbProgramData;
@@ -32,6 +31,7 @@
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.util.BitwiseOutputStream;
+import com.android.telephony.Rlog;
 
 import org.junit.Ignore;
 import org.junit.Test;
@@ -353,7 +353,7 @@
         SmsMessage msg = createBroadcastSmsMessage(123, 456, BearerData.PRIORITY_NORMAL,
                 BearerData.LANGUAGE_ENGLISH, encoding, TEST_TEXT);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         verifyCbValues(cbMessage);
         assertEquals(123, cbMessage.getServiceCategory());
         assertEquals(456, cbMessage.getSerialNumber());
@@ -385,7 +385,7 @@
         SmsMessage msg = createBroadcastSmsMessage(987, 654, -1, -1,
                 UserData.ENCODING_IS91_EXTENDED_PROTOCOL, IS91_TEXT);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         verifyCbValues(cbMessage);
         assertEquals(987, cbMessage.getServiceCategory());
         assertEquals(654, cbMessage.getSerialNumber());
@@ -402,7 +402,7 @@
                 serviceCategory, 1234, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
                 UserData.ENCODING_7BIT_ASCII, body, -1, -1, -1, -1, -1);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         verifyCbValues(cbMessage);
         assertEquals(serviceCategory, cbMessage.getServiceCategory());
         assertEquals(1234, cbMessage.getSerialNumber());
@@ -458,7 +458,7 @@
                 SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR, SmsCbCmasInfo.CMAS_SEVERITY_SEVERE,
                 SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         verifyCbValues(cbMessage);
         assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT,
                 cbMessage.getServiceCategory());
@@ -488,7 +488,7 @@
                 12345, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
                 0x1F, EXTREME_ALERT, -1, -1, -1, -1, -1);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         assertNull("expected null for unsupported charset", cbMessage);
     }
 
@@ -500,7 +500,7 @@
                 67890, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
                 UserData.ENCODING_KOREAN, EXTREME_ALERT, -1, -1, -1, -1, -1);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         assertNull("expected null for unsupported charset", cbMessage);
     }
 
@@ -513,7 +513,7 @@
                 BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
                 UserData.ENCODING_7BIT_ASCII, null, -1, -1, -1, -1, -1);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         verifyCbValues(cbMessage);
         assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT,
                 cbMessage.getServiceCategory());
@@ -547,7 +547,7 @@
                 int category = 0x0ff0 + r.nextInt(32);  // half CMAS, half non-CMAS
                 CdmaSmsMessage cdmaSmsMessage = createBroadcastParcel(category);
                 SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, data);
-                SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+                SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
                 // with random input, cbMessage will almost always be null (log when it isn't)
                 if (cbMessage != null) {
                     Rlog.d("CdmaSmsCbTest", "success: " + cbMessage);
@@ -581,7 +581,7 @@
                 }
 
                 SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, bos.toByteArray());
-                SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+                SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
             } catch (Exception e) {
                 Rlog.d("CdmaSmsCbTest", "exception thrown", e);
                 fail("Exception in decoder at run " + run + " length " + len + ": " + e);
@@ -744,7 +744,7 @@
         CdmaSmsMessage cdmaSmsMessage = createBroadcastParcel(SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE);
         SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, CMAS_TEST_BEARER_DATA);
 
-        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+        SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0, 1);
         assertNotNull("expected non-null for bearer data", cbMessage);
         assertEquals("geoScope", cbMessage.getGeographicalScope(), 1);
         assertEquals("serialNumber", cbMessage.getSerialNumber(), 51072);
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/DataCallResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataCallResponseTest.java
index 20f3d8b..529e81e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataCallResponseTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataCallResponseTest.java
@@ -22,8 +22,8 @@
 import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME;
 import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS;
 
+import android.net.InetAddresses;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
 import android.os.Parcel;
 import android.telephony.data.ApnSetting;
 import android.telephony.data.DataCallResponse;
@@ -36,13 +36,22 @@
 
     @SmallTest
     public void testParcel() throws Exception {
-        DataCallResponse response = new DataCallResponse(0, -1, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
 
         Parcel p = Parcel.obtain();
         response.writeToParcel(p, 0);
@@ -54,34 +63,62 @@
 
     @SmallTest
     public void testEquals() throws Exception {
-        DataCallResponse response = new DataCallResponse(0, -1, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1400)
+                .build();
 
-        DataCallResponse response1 = new DataCallResponse(0, -1, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        DataCallResponse response1 = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1400)
+                .build();
 
         assertEquals(response, response);
         assertEquals(response, response1);
 
-        DataCallResponse response2 = new DataCallResponse(1, -1, 1, 3,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS),
-                        NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS),
-                        NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1441);
+        DataCallResponse response2 = new DataCallResponse.Builder()
+                .setCause(1)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(3)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS),
+                        InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(Arrays.asList(
+                        InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS),
+                        InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1441)
+                .setMtuV6(1440)
+                .build();
+
         assertNotSame(response1, response2);
         assertNotSame(response1, null);
         assertNotSame(response1, new String[1]);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index 018747e..851ae35 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -18,8 +18,8 @@
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
-import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
+import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED;
+import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
 
 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
 import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS;
@@ -40,13 +40,13 @@
 
 import android.content.IntentFilter;
 import android.content.pm.ServiceInfo;
+import android.net.InetAddresses;
 import android.net.KeepalivePacketData;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NattKeepalivePacketData;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
-import android.net.NetworkUtils;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -420,77 +420,138 @@
     @Test
     @SmallTest
     public void testModemSuggestRetry() throws Exception {
-        DataCallResponse response = new DataCallResponse(0, 0, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
-
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(0)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response));
 
-        response = new DataCallResponse(0, 1000, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(1000)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response));
 
-        response = new DataCallResponse(0, 9999, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(9999)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response));
     }
 
     @Test
     @SmallTest
     public void testModemNotSuggestRetry() throws Exception {
-        DataCallResponse response = new DataCallResponse(0, -1, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
-
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response));
 
-        response = new DataCallResponse(0, -5, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-5)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response));
 
-        response = new DataCallResponse(0, Integer.MIN_VALUE, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(Integer.MIN_VALUE)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response));
     }
 
     @Test
     @SmallTest
     public void testModemSuggestNoRetry() throws Exception {
-        DataCallResponse response = new DataCallResponse(0, Integer.MAX_VALUE, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(Integer.MAX_VALUE)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         assertEquals(RetryManager.NO_RETRY, getSuggestedRetryDelay(response));
     }
 
@@ -585,12 +646,13 @@
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
-        mDc.onSubscriptionOverride(OVERRIDE_UNMETERED, OVERRIDE_UNMETERED);
+        mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_UNMETERED,
+                SUBSCRIPTION_OVERRIDE_UNMETERED);
 
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
-        mDc.onSubscriptionOverride(OVERRIDE_UNMETERED, 0);
+        mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_UNMETERED, 0);
 
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
@@ -606,12 +668,13 @@
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
-        mDc.onSubscriptionOverride(OVERRIDE_CONGESTED, OVERRIDE_CONGESTED);
+        mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_CONGESTED,
+                SUBSCRIPTION_OVERRIDE_CONGESTED);
 
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
-        mDc.onSubscriptionOverride(OVERRIDE_CONGESTED, 0);
+        mDc.onSubscriptionOverride(SUBSCRIPTION_OVERRIDE_CONGESTED, 0);
 
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
@@ -670,14 +733,22 @@
     @Test
     @SmallTest
     public void testSetLinkProperties() throws Exception {
-
-        DataCallResponse response = new DataCallResponse(0, -1, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
 
         LinkProperties linkProperties = new LinkProperties();
         assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties));
@@ -686,28 +757,28 @@
         assertEquals(response.getAddresses().size(), linkProperties.getAddresses().size());
         for (int i = 0; i < response.getAddresses().size(); ++i) {
             assertEquals(response.getAddresses().get(i).getAddress(),
-                    NetworkUtils.numericToInetAddress(linkProperties.getLinkAddresses().get(i)
+                    InetAddresses.parseNumericAddress(linkProperties.getLinkAddresses().get(i)
                             .getAddress().getHostAddress()));
         }
 
         assertEquals(response.getDnsAddresses().size(), linkProperties.getDnsServers().size());
         for (int i = 0; i < response.getDnsAddresses().size(); ++i) {
             assertEquals("i = " + i, response.getDnsAddresses().get(i),
-                    NetworkUtils.numericToInetAddress(
+                    InetAddresses.parseNumericAddress(
                             linkProperties.getDnsServers().get(i).getHostAddress()));
         }
 
         assertEquals(response.getGatewayAddresses().size(), linkProperties.getRoutes().size());
         for (int i = 0; i < response.getGatewayAddresses().size(); ++i) {
             assertEquals("i = " + i, response.getGatewayAddresses().get(i),
-                    NetworkUtils.numericToInetAddress(linkProperties.getRoutes().get(i)
+                    InetAddresses.parseNumericAddress(linkProperties.getRoutes().get(i)
                             .getGateway().getHostAddress()));
         }
 
         assertEquals(response.getPcscfAddresses().size(), linkProperties.getPcscfServers().size());
         for (int i = 0; i < response.getPcscfAddresses().size(); ++i) {
             assertEquals("i = " + i, response.getPcscfAddresses().get(i),
-                    NetworkUtils.numericToInetAddress(linkProperties.getPcscfServers().get(i)
+                    InetAddresses.parseNumericAddress(linkProperties.getPcscfServers().get(i)
                             .getHostAddress()));
         }
 
@@ -717,33 +788,45 @@
     @Test
     @SmallTest
     public void testSetLinkPropertiesEmptyAddress() throws Exception {
-
         // 224.224.224.224 is an invalid address.
-        DataCallResponse response = new DataCallResponse(0, -1, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                null,
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
 
         LinkProperties linkProperties = new LinkProperties();
-        assertEquals(SetupResult.ERROR_INVALID_ARG,
-                setLinkProperties(response, linkProperties));
+        assertEquals(SetupResult.ERROR_INVALID_ARG, setLinkProperties(response, linkProperties));
     }
 
     @Test
     @SmallTest
     public void testSetLinkPropertiesEmptyDns() throws Exception {
-
         // Empty dns entry.
-        DataCallResponse response = new DataCallResponse(0, -1, 1, 2,
-                ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                null,
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(2)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
 
         // Make sure no exception was thrown
         LinkProperties linkProperties = new LinkProperties();
@@ -766,9 +849,9 @@
         // Construct a new KeepalivePacketData request as we would receive from a Network Agent,
         // and check that the packet is sent to the RIL.
         KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket(
-                NetworkUtils.numericToInetAddress("1.2.3.4"),
+                InetAddresses.parseNumericAddress("1.2.3.4"),
                 1234,
-                NetworkUtils.numericToInetAddress("8.8.8.8"),
+                InetAddresses.parseNumericAddress("8.8.8.8"),
                 4500);
         mDc.obtainMessage(
                 DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget();
@@ -790,9 +873,9 @@
         // Construct a new KeepalivePacketData request as we would receive from a Network Agent,
         // and check that the packet is sent to the RIL.
         KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket(
-                NetworkUtils.numericToInetAddress("1.2.3.4"),
+                InetAddresses.parseNumericAddress("1.2.3.4"),
                 1234,
-                NetworkUtils.numericToInetAddress("8.8.8.8"),
+                InetAddresses.parseNumericAddress("8.8.8.8"),
                 4500);
         mDc.obtainMessage(
                 DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget();
@@ -869,9 +952,9 @@
         // Construct a new KeepalivePacketData request as we would receive from a Network Agent,
         // and check that the packet is sent to the RIL.
         KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket(
-                NetworkUtils.numericToInetAddress("1.2.3.4"),
+                InetAddresses.parseNumericAddress("1.2.3.4"),
                 1234,
-                NetworkUtils.numericToInetAddress("8.8.8.8"),
+                InetAddresses.parseNumericAddress("8.8.8.8"),
                 4500);
         mDc.obtainMessage(
                 DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataFailCauseTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataFailCauseTest.java
index e881cc9..24d9bd6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataFailCauseTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataFailCauseTest.java
@@ -138,9 +138,7 @@
         mFailCauseDataList.add(new DcFailCauseData(0x10000, false, false));
         mFailCauseDataList.add(new DcFailCauseData(0x10001, true, false));
         mFailCauseDataList.add(new DcFailCauseData(0x10002, true, true));
-        mFailCauseDataList.add(new DcFailCauseData(0x10003, false, false));
         mFailCauseDataList.add(new DcFailCauseData(0x10004, false, false));
-        mFailCauseDataList.add(new DcFailCauseData(0x10005, false, false));
 
         CarrierConfigManager configManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
index 7058ce3..9c1d1a8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
@@ -30,9 +30,9 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.net.InetAddresses;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.NetworkUtils;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
@@ -115,15 +115,23 @@
     @SmallTest
     public void testDataDormant() throws Exception {
         assertEquals("DccDefaultState", getCurrentState().getName());
-        ArrayList<DataCallResponse> l = new ArrayList<DataCallResponse>();
-        DataCallResponse dcResponse = new DataCallResponse(0, -1, 1,
-                DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT, ApnSetting.PROTOCOL_IP, FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)),
-                1440);
-
+        ArrayList<DataCallResponse> l = new ArrayList<>();
+        DataCallResponse dcResponse = new DataCallResponse.Builder()
+                .setCause(0)
+                .setSuggestedRetryTime(-1)
+                .setId(1)
+                .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT)
+                .setProtocolType(ApnSetting.PROTOCOL_IP)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
         l.add(dcResponse);
 
         mDc.mCid = 1;
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 101c719..a840c3b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -51,6 +51,7 @@
 import android.net.LinkProperties;
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkRequest;
 import android.net.Uri;
 import android.os.AsyncResult;
@@ -66,8 +67,10 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionPlan;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.telephony.data.DataProfile;
@@ -97,9 +100,16 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.time.Period;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class DcTrackerTest extends TelephonyTest {
 
@@ -108,7 +118,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";
@@ -145,6 +156,8 @@
     PackageManagerService mMockPackageManagerInternal;
     @Mock
     Handler mHandler;
+    @Mock
+    NetworkPolicyManager mNetworkPolicyManager;
 
     private DcTracker mDct;
     private DcTrackerTestHandler mDcTrackerTestHandler;
@@ -434,7 +447,7 @@
 
                     return mc;
                 }
-            } else if (uri.isPathPrefixMatch(
+            } else if (isPathPrefixMatch(uri,
                     Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapnset"))) {
                 MatrixCursor mc = new MatrixCursor(
                         new String[]{Telephony.Carriers.APN_SET_ID});
@@ -503,7 +516,8 @@
                 }
         ).when(mSubscriptionManager).addOnSubscriptionsChangedListener(any());
         doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
-
+        doReturn(mNetworkPolicyManager).when(mContext)
+                .getSystemService(Context.NETWORK_POLICY_SERVICE);
         doReturn(1).when(mIsub).getDefaultDataSubId();
         doReturn(mIsub).when(mBinder).queryLocalInterface(anyString());
         mServiceManagerMockedServices.put("isub", mBinder);
@@ -720,21 +734,14 @@
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
-        // Verify the retry manger schedule another data call setup.
-        verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
-                anyLong(), any(PendingIntent.class));
-
         // This time we'll let RIL command succeed.
         mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
 
-        // Simulate the timer expires.
-        Intent intent = new Intent("com.android.internal.telephony.data-reconnect.default");
-        intent.putExtra("reconnect_alarm_extra_type", PhoneConstants.APN_TYPE_DEFAULT);
-        intent.putExtra("reconnect_alarm_extra_transport_type",
-                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, 0);
-        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        mContext.sendBroadcast(intent);
+        //Send event for reconnecting data
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
+                        mPhone.getPhoneId(), AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                        mApnContext));
         waitForMs(200);
 
         dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
@@ -1079,9 +1086,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
@@ -1361,14 +1385,11 @@
         verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
                 anyLong(), any(PendingIntent.class));
 
-        // Simulate the timer expires.
-        Intent intent = new Intent("com.android.internal.telephony.data-reconnect.default");
-        intent.putExtra("reconnect_alarm_extra_type", PhoneConstants.APN_TYPE_DEFAULT);
-        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, 0);
-        intent.putExtra("reconnect_alarm_extra_transport_type",
-                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        mContext.sendBroadcast(intent);
+        //Send event for reconnecting data
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
+                        mPhone.getPhoneId(), AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                        mApnContext));
         waitForMs(200);
 
         // Verify if RIL command was sent properly.
@@ -1597,16 +1618,17 @@
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
+        waitForMs(200);
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                NetworkAgent.VALID_NETWORK, 0, null));
+                NetworkAgent.VALID_NETWORK, 1, null));
         waitForMs(200);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                NetworkAgent.INVALID_NETWORK, 0, null));
+                NetworkAgent.INVALID_NETWORK, 1, null));
         waitForMs(200);
 
         // Verify that its no-op when the new data stall detection feature is disabled
@@ -1620,6 +1642,7 @@
         ContentResolver resolver = mContext.getContentResolver();
         Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
         Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 0);
+        doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
@@ -1638,16 +1661,17 @@
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
+        waitForMs(200);
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                NetworkAgent.VALID_NETWORK, 0, null));
+                NetworkAgent.VALID_NETWORK, 1, null));
         waitForMs(200);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                NetworkAgent.INVALID_NETWORK, 0, null));
+                NetworkAgent.INVALID_NETWORK, 1, null));
         waitForMs(200);
 
         verify(mSimulatedCommandsVerifier, times(1)).getDataCallList(any(Message.class));
@@ -1662,6 +1686,7 @@
         Settings.Global.putLong(resolver,
                 Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
         Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 1);
+        doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
@@ -1680,11 +1705,12 @@
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
+        waitForMs(200);
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                NetworkAgent.INVALID_NETWORK, 0, null));
+                NetworkAgent.INVALID_NETWORK, 1, null));
         waitForMs(200);
 
         // expected tear down all DataConnections
@@ -1702,6 +1728,7 @@
         Settings.Global.putLong(resolver,
                 Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
         Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2);
+        doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
@@ -1724,7 +1751,7 @@
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                NetworkAgent.INVALID_NETWORK, 0, null));
+                NetworkAgent.INVALID_NETWORK, 1, null));
         waitForMs(200);
 
         // expected to get preferred network type
@@ -1739,6 +1766,7 @@
         Settings.Global.putLong(resolver,
                 Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
         Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3);
+        doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
@@ -1761,7 +1789,7 @@
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
-                NetworkAgent.INVALID_NETWORK, 0, null));
+                NetworkAgent.INVALID_NETWORK, 1, null));
         waitForMs(200);
 
         // expected to get preferred network type
@@ -1776,4 +1804,241 @@
         assertEquals(reason, (int) result.second);
         clearInvocations(mHandler);
     }
+
+    private void setUpSubscriptionPlans(boolean is5GUnmetered) throws Exception {
+        List<SubscriptionPlan> plans = new ArrayList<>();
+        if (is5GUnmetered) {
+            plans.add(SubscriptionPlan.Builder
+                    .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"),
+                            Period.ofMonths(1))
+                    .setTitle("Some NR 5G unmetered workaround plan")
+                    .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED,
+                            SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
+                    .setNetworkTypes(new int[] {TelephonyManager.NETWORK_TYPE_NR})
+                    .build());
+        }
+        plans.add(SubscriptionPlan.Builder
+                .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"),
+                        Period.ofMonths(1))
+                .setTitle("Some 5GB Plan")
+                .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
+                .setDataUsage(500_000_000, System.currentTimeMillis())
+                .build());
+        replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans);
+    }
+
+    private boolean isNetworkTypeUnmetered(int networkType) throws Exception {
+        Method method = DcTracker.class.getDeclaredMethod(
+                "isNetworkTypeUnmetered", int.class);
+        method.setAccessible(true);
+        return (boolean) method.invoke(mDct, networkType);
+    }
+
+    private void setUpDataConnection() throws Exception {
+        Field dc = DcTracker.class.getDeclaredField("mDataConnections");
+        dc.setAccessible(true);
+        Field uig = DcTracker.class.getDeclaredField("mUniqueIdGenerator");
+        uig.setAccessible(true);
+        ((HashMap<Integer, DataConnection>) dc.get(mDct)).put(
+                ((AtomicInteger) uig.get(mDct)).getAndIncrement(), mDataConnection);
+    }
+
+    private void setUpWatchdogTimer() {
+        // Watchdog active for 10s
+        mBundle.putLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG, 10000);
+        Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
+        mContext.sendBroadcast(intent);
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+    }
+
+    private boolean getHysteresisStatus() throws Exception {
+        Field field = DcTracker.class.getDeclaredField(("mHysteresis"));
+        field.setAccessible(true);
+        return (boolean) field.get(mDct);
+    }
+
+    private boolean getWatchdogStatus() throws Exception {
+        Field field = DcTracker.class.getDeclaredField(("mWatchdog"));
+        field.setAccessible(true);
+        return (boolean) field.get(mDct);
+    }
+
+    @Test
+    public void testIsNetworkTypeUnmetered() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+
+        // only 5G unmetered
+        setUpSubscriptionPlans(true);
+
+        assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
+        assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
+        assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
+
+        // all network types metered
+        setUpSubscriptionPlans(false);
+
+        assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
+        assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
+        assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
+
+        // all network types unmetered
+        List<SubscriptionPlan> plans = new ArrayList<>();
+        plans.add(SubscriptionPlan.Builder
+                .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"),
+                        Period.ofMonths(1))
+                .setTitle("Some 5GB Plan")
+                .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED,
+                        SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
+                .build());
+        replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans);
+
+        assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
+        assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
+        assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
+    }
+
+    @Test
+    public void testReevaluateUnmeteredConnectionsOnNetworkChange() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        setUpDataConnection();
+        setUpSubscriptionPlans(true);
+        setUpWatchdogTimer();
+
+        // NetCapability should be unmetered when connected to 5G
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        verify(mDataConnection, times(1)).onMeterednessChanged(true);
+
+        // NetCapability should be metered when disconnected from 5G
+        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        verify(mDataConnection, times(1)).onMeterednessChanged(false);
+    }
+
+    @Test
+    public void testReevaluateUnmeteredConnectionsOnHysteresis() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        setUpDataConnection();
+        setUpSubscriptionPlans(true);
+        setUpWatchdogTimer();
+
+        // Hysteresis active for 10s
+        mBundle.putLong(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 10000);
+        Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
+        mContext.sendBroadcast(intent);
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+
+        // Hysteresis inactive when unmetered and never connected to 5G
+        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_5G_TIMER_HYSTERESIS));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertFalse(getHysteresisStatus());
+
+        // Hysteresis inactive when unmetered and connected to 5G
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertFalse(getHysteresisStatus());
+
+        // Hysteresis active when unmetered and disconnected after connected to 5G
+        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertTrue(getHysteresisStatus());
+
+        // NetCapability metered when hysteresis timer goes off
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_5G_TIMER_HYSTERESIS));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertFalse(getHysteresisStatus());
+        verify(mDataConnection, times(1)).onMeterednessChanged(true);
+
+        // Hysteresis inactive when reconnected after timer goes off
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertFalse(getHysteresisStatus());
+
+        // Hysteresis disabled
+        mBundle.putLong(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0);
+        intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
+        mContext.sendBroadcast(intent);
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+
+        // Hysteresis inactive when CarrierConfig is set to 0
+        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertFalse(getHysteresisStatus());
+    }
+
+    @Test
+    public void testReevaluateUnmeteredConnectionsOnWatchdog() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        setUpDataConnection();
+        setUpSubscriptionPlans(true);
+        setUpWatchdogTimer();
+
+        // Watchdog inactive when unmetered and never connected to 5G
+        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_5G_TIMER_WATCHDOG));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertFalse(getWatchdogStatus());
+
+        // Hysteresis active for 10s
+        mBundle.putLong(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 10000);
+        Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
+        mContext.sendBroadcast(intent);
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+
+        // Watchdog active when unmetered and connected to 5G
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertTrue(getWatchdogStatus());
+        assertFalse(getHysteresisStatus());
+
+        // Watchdog active during hysteresis
+        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertTrue(getHysteresisStatus());
+        assertTrue(getWatchdogStatus());
+
+        // Watchdog inactive when metered
+        setUpSubscriptionPlans(false);
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SERVICE_STATE_CHANGED));
+        waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
+        assertFalse(getWatchdogStatus());
+    }
+
+    /**
+     * Test if this is a path prefix match against the given Uri. Verifies that
+     * scheme, authority, and atomic path segments match.
+     *
+     * Copied from frameworks/base/core/java/android/net/Uri.java
+     */
+    private boolean isPathPrefixMatch(Uri uriA, Uri uriB) {
+        if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false;
+        if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false;
+
+        List<String> segA = uriA.getPathSegments();
+        List<String> segB = uriB.getPathSegments();
+
+        final int size = segB.size();
+        if (segA.size() < size) return false;
+
+        for (int i = 0; i < size; i++) {
+            if (!Objects.equals(segA.get(i), segB.get(i))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
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 bb604f4..8f7bc4f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
@@ -16,27 +16,29 @@
 
 package com.android.internal.telephony.dataconnection;
 
+import static android.net.NetworkFactory.CMD_CANCEL_REQUEST;
+import static android.net.NetworkFactory.CMD_REQUEST_NETWORK;
+
+import static com.android.internal.telephony.dataconnection.TelephonyNetworkFactory.EVENT_ACTIVE_PHONE_SWITCH;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 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.content.Context;
-import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
 import android.os.AsyncResult;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Messenger;
 import android.telephony.AccessNetworkConstants;
-import android.telephony.Rlog;
 import android.telephony.data.ApnSetting;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -46,21 +48,17 @@
 
 import com.android.internal.telephony.PhoneSwitcher;
 import com.android.internal.telephony.RadioConfig;
-import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams;
 import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams.HandoverCallback;
-import com.android.internal.telephony.mocks.ConnectivityServiceMock;
-import com.android.internal.telephony.mocks.PhoneSwitcherMock;
-import com.android.internal.telephony.mocks.SubscriptionControllerMock;
-import com.android.internal.telephony.mocks.SubscriptionMonitorMock;
-import com.android.internal.telephony.mocks.TelephonyRegistryMock;
+import com.android.telephony.Rlog;
 
 import org.junit.After;
 import org.junit.Before;
 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;
@@ -71,20 +69,19 @@
     private final static String LOG_TAG = "TelephonyNetworkFactoryTest";
 
     @Mock
-    private RadioConfig mMockRadioConfig;
+    PhoneSwitcher mPhoneSwitcher;
     @Mock
-    private IConnectivityManager mIConnectivityManager;
+    private RadioConfig mMockRadioConfig;
+
+    @Mock
+    private DataConnection mDataConnection;
 
     private String mTestName = "";
 
-    private TelephonyRegistryMock mTelephonyRegistryMock;
-    private PhoneSwitcherMock mPhoneSwitcherMock;
-    private SubscriptionControllerMock mSubscriptionControllerMock;
-    private SubscriptionMonitorMock mSubscriptionMonitorMock;
-    private ConnectivityServiceMock mConnectivityServiceMock;
     private final ArrayList<NetworkRequest> mNetworkRequestList = new ArrayList<>();
 
     private TelephonyNetworkFactory mTelephonyNetworkFactoryUT;
+    private int mRequestId = 0;
 
     private void log(String str) {
         Rlog.d(LOG_TAG + " " + mTestName, str);
@@ -95,16 +92,54 @@
                 addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).
                 addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
                 addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
-        return mConnectivityServiceMock.requestNetwork(netCap, null, 0, new Binder(), -1);
+        netCap.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                .setSubscriptionId(subId).build());
+        NetworkRequest networkRequest = new NetworkRequest(netCap, -1,
+                mRequestId++, NetworkRequest.Type.REQUEST);
+        mTelephonyNetworkFactoryUT.obtainMessage(CMD_REQUEST_NETWORK, 0, 0, networkRequest)
+                .sendToTarget();
+        return networkRequest;
     }
+
+    private NetworkRequest makeDefaultInternetRequest() {
+        NetworkCapabilities netCap = (new NetworkCapabilities())
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        NetworkRequest networkRequest = new NetworkRequest(netCap, -1,
+                mRequestId++, NetworkRequest.Type.REQUEST);
+        mTelephonyNetworkFactoryUT.obtainMessage(CMD_REQUEST_NETWORK, 0, 0, networkRequest)
+                .sendToTarget();
+        return networkRequest;
+    }
+
     private NetworkRequest makeSubSpecificMmsRequest(int subId) {
         NetworkCapabilities netCap = (new NetworkCapabilities()).
                 addCapability(NetworkCapabilities.NET_CAPABILITY_MMS).
                 addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
                 addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
-        return mConnectivityServiceMock.requestNetwork(netCap, null, 0, new Binder(), -1);
+        netCap.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                .setSubscriptionId(subId).build());
+        NetworkRequest networkRequest = new NetworkRequest(netCap, -1,
+                mRequestId++, NetworkRequest.Type.REQUEST);
+        mTelephonyNetworkFactoryUT.obtainMessage(CMD_REQUEST_NETWORK, 0, 0, networkRequest)
+                .sendToTarget();
+        return networkRequest;
+    }
+
+    private void releaseNetworkRequest(NetworkRequest networkRequest) {
+        mTelephonyNetworkFactoryUT.obtainMessage(CMD_CANCEL_REQUEST, 0, 0, networkRequest)
+                .sendToTarget();
+    }
+
+    private void activatePhoneInPhoneSwitcher(int phoneId, boolean active) {
+        doReturn(active).when(mPhoneSwitcher).shouldApplyNetworkRequest(any(), eq(phoneId));
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(EVENT_ACTIVE_PHONE_SWITCH);
+    }
+
+    private void activatePhoneInPhoneSwitcher(int phoneId, NetworkRequest nr, boolean active) {
+        doReturn(active).when(mPhoneSwitcher).shouldApplyNetworkRequest(eq(nr), eq(phoneId));
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(EVENT_ACTIVE_PHONE_SWITCH);
     }
 
     @Before
@@ -129,47 +164,19 @@
             mNetworkRequestList.remove((NetworkRequest) invocation.getArguments()[0]);
             return null;
         }).when(mDcTracker).releaseNetwork(any(), anyInt());
-
-        doAnswer(invocation -> {
-            mConnectivityServiceMock.registerNetworkFactory(
-                    (Messenger) invocation.getArguments()[0],
-                    (String) invocation.getArguments()[1]);
-            return null;
-        }).when(mIConnectivityManager).registerNetworkFactory(any(), anyString());
-
-        doAnswer(invocation -> {
-            mConnectivityServiceMock.unregisterNetworkFactory(
-                    (Messenger) invocation.getArguments()[0]);
-            return null;
-        }).when(mIConnectivityManager).unregisterNetworkFactory(any());
     }
 
     @After
     public void tearDown() throws Exception {
-        mConnectivityServiceMock.die();
         super.tearDown();
     }
 
-    private void createMockedTelephonyComponents(int numberOfPhones) throws Exception {
-        mConnectivityServiceMock = new ConnectivityServiceMock(mContext);
-        mContextFixture.setSystemService(Context.CONNECTIVITY_SERVICE,
-                new ConnectivityManager(mContext, mIConnectivityManager));
-        mTelephonyRegistryMock = new TelephonyRegistryMock();
-        mSubscriptionControllerMock = new SubscriptionControllerMock(mContext,
-                mTelephonyRegistryMock, numberOfPhones);
-        mSubscriptionMonitorMock = new SubscriptionMonitorMock(numberOfPhones);
-        mPhoneSwitcherMock = new PhoneSwitcherMock(
-                numberOfPhones, Looper.myLooper(), mSubscriptionControllerMock);
-        mSubscriptionMonitorMock = new SubscriptionMonitorMock(numberOfPhones);
+    private void createMockedTelephonyComponents() throws Exception {
+        replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcher);
 
-        replaceInstance(SubscriptionController.class, "sInstance", null,
-                mSubscriptionControllerMock);
-        replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcherMock);
-
-        mTelephonyNetworkFactoryUT = new TelephonyNetworkFactory(mSubscriptionMonitorMock,
-                Looper.myLooper(), mPhone);
-        monitorTestableLooper(new TestableLooper(
-                mConnectivityServiceMock.getHandlerThread().getLooper()));
+        mTelephonyNetworkFactoryUT = new TelephonyNetworkFactory(Looper.myLooper(), mPhone);
+        verify(mConnectivityManager).registerNetworkProvider(any());
+        verify(mPhoneSwitcher).registerForActivePhoneSwitch(any(), anyInt(), any());
     }
 
     /**
@@ -180,24 +187,25 @@
     @SmallTest
     public void testActive() throws Exception {
         mTestName = "testActive";
-        final int numberOfPhones = 1;
         final int phoneId = 0;
         final int subId = 0;
 
-        createMockedTelephonyComponents(numberOfPhones);
+        createMockedTelephonyComponents();
 
-        mPhoneSwitcherMock.setPreferredDataPhoneId(phoneId);
-        mSubscriptionControllerMock.setDefaultDataSubId(subId);
-        mSubscriptionControllerMock.setSlotSubId(phoneId, subId);
-        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        doReturn(false).when(mPhoneSwitcher).shouldApplyNetworkRequest(any(), anyInt());
+        doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
+        // fake onSubscriptionChangedListener being triggered.
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
+                TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
 
         log("addDefaultRequest");
-        mConnectivityServiceMock.addDefaultRequest();
+        makeDefaultInternetRequest();
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
         log("setPhoneActive true: phoneId = " + phoneId);
-        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+
+        activatePhoneInPhoneSwitcher(phoneId, true);
         processAllMessages();
         assertEquals(1, mNetworkRequestList.size());
 
@@ -207,7 +215,7 @@
         assertEquals(2, mNetworkRequestList.size());
 
         log("setPhoneActive false: phoneId = " + phoneId);
-        mPhoneSwitcherMock.setPhoneActive(phoneId, false);
+        activatePhoneInPhoneSwitcher(phoneId, false);
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
@@ -217,27 +225,27 @@
         assertEquals(0, mNetworkRequestList.size());
 
         log("setPhoneActive true: phoneId = " + phoneId);
-        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+        activatePhoneInPhoneSwitcher(phoneId, true);
         processAllMessages();
         assertEquals(3, mNetworkRequestList.size());
 
         log("releaseNetworkRequest: subSpecificDefault = " + subSpecificDefault);
-        mConnectivityServiceMock.releaseNetworkRequest(subSpecificDefault);
+        releaseNetworkRequest(subSpecificDefault);
         processAllMessages();
         assertEquals(2, mNetworkRequestList.size());
 
         log("setPhoneActive false: phoneId = " + phoneId);
-        mPhoneSwitcherMock.setPhoneActive(phoneId, false);
+        activatePhoneInPhoneSwitcher(phoneId, false);
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
         log("releaseNetworkRequest: subSpecificMms = " + subSpecificMms);
-        mConnectivityServiceMock.releaseNetworkRequest(subSpecificMms);
+        releaseNetworkRequest(subSpecificMms);
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
         log("setPhoneActive true: phoneId = " + phoneId);
-        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+        activatePhoneInPhoneSwitcher(phoneId, true);
         processAllMessages();
         assertEquals(1, mNetworkRequestList.size());
     }
@@ -256,39 +264,39 @@
         final int altSubId = 1;
         final int unusedSubId = 2;
 
-        createMockedTelephonyComponents(numberOfPhones);
+        createMockedTelephonyComponents();
 
-        mPhoneSwitcherMock.setPreferredDataPhoneId(phoneId);
-        mSubscriptionControllerMock.setDefaultDataSubId(subId);
-        mSubscriptionControllerMock.setSlotSubId(phoneId, subId);
-        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
+                TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
-        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+        activatePhoneInPhoneSwitcher(phoneId, true);
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
-        mConnectivityServiceMock.addDefaultRequest();
+        makeDefaultInternetRequest();
         processAllMessages();
         assertEquals(1, mNetworkRequestList.size());
 
-        mSubscriptionControllerMock.setSlotSubId(altPhoneId, altSubId);
+        doReturn(altSubId).when(mSubscriptionController).getSubIdUsingPhoneId(altPhoneId);
         processAllMessages();
         assertEquals(1, mNetworkRequestList.size());
 
-        mPhoneSwitcherMock.setPreferredDataPhoneId(altPhoneId);
-        mSubscriptionControllerMock.setDefaultDataSubId(altSubId);
-        mPhoneSwitcherMock.notifyActivePhoneChange(phoneId);
+        activatePhoneInPhoneSwitcher(phoneId, false);
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(EVENT_ACTIVE_PHONE_SWITCH);
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
-        makeSubSpecificMmsRequest(subId);
+        NetworkRequest subSpecificMmsRequest = makeSubSpecificMmsRequest(subId);
+        activatePhoneInPhoneSwitcher(phoneId, subSpecificMmsRequest, true);
         processAllMessages();
         assertEquals(1, mNetworkRequestList.size());
 
-        mSubscriptionControllerMock.setSlotSubId(phoneId, unusedSubId);
-        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        doReturn(unusedSubId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
+                TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
@@ -296,13 +304,12 @@
         processAllMessages();
         assertEquals(0, mNetworkRequestList.size());
 
-        mSubscriptionControllerMock.setSlotSubId(phoneId, subId);
-        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
+                TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
         processAllMessages();
 
-        mSubscriptionControllerMock.setDefaultDataSubId(subId);
-        mPhoneSwitcherMock.setPreferredDataPhoneId(phoneId);
-        mPhoneSwitcherMock.notifyActivePhoneChange(phoneId);
+        activatePhoneInPhoneSwitcher(phoneId, true);
         processAllMessages();
         assertEquals(3, mNetworkRequestList.size());
     }
@@ -313,14 +320,13 @@
     @Test
     @SmallTest
     public void testHandoverNoLiveData() throws Exception {
-        createMockedTelephonyComponents(1);
-        mPhoneSwitcherMock.setPreferredDataPhoneId(0);
-        mSubscriptionControllerMock.setDefaultDataSubId(0);
-        mSubscriptionControllerMock.setSlotSubId(0, 0);
-        mSubscriptionMonitorMock.notifySubscriptionChanged(0);
+        createMockedTelephonyComponents();
+        doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0);
+        mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
+                TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
 
-        mPhoneSwitcherMock.setPhoneActive(0, true);
-        mConnectivityServiceMock.addDefaultRequest();
+        activatePhoneInPhoneSwitcher(0, true);
+        makeDefaultInternetRequest();
 
         makeSubSpecificMmsRequest(0);
         processAllMessages();
@@ -346,4 +352,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/euicc/EuiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
index 3d45af3..cfd9eb2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
@@ -1082,7 +1082,7 @@
         SubscriptionInfo subInfo = new SubscriptionInfo(
                 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */,
                 hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID,
-                false, null, false, 0, 0, 0, null, null);
+                false, null, false, 0, 0, 0, null, null, true);
         when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn(
                 hasPrivileges);
         when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
@@ -1103,11 +1103,11 @@
         SubscriptionInfo subInfo1 = new SubscriptionInfo(
                 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */,
                 hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID,
-                false, null, false, 0, 0, 0, null, null);
+                false, null, false, 0, 0, 0, null, null, true);
         SubscriptionInfo subInfo2 = new SubscriptionInfo(
                 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */,
                 hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "",
-                1 /* cardId */, false, null, false, 0, 0, 0, null, null);
+                1 /* cardId */, false, null, false, 0, 0, 0, null, null, true);
         when(mSubscriptionManager.canManageSubscription(subInfo1, PACKAGE_NAME)).thenReturn(
                 hasPrivileges);
         when(mSubscriptionManager.canManageSubscription(subInfo2, PACKAGE_NAME)).thenReturn(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken
index aa94e0e..16861fa 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken
@@ -22,7 +22,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 
 import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.test.SimulatedCommands;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
deleted file mode 100644
index 18bc486..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.gsm;
-
-import static android.provider.Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.nullable;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.Manifest;
-import android.app.Activity;
-import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Telephony;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import com.android.internal.telephony.SmsStorageMonitor;
-import com.android.internal.telephony.TelephonyTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-
-import java.util.List;
-
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class GsmCellBroadcastHandlerTest extends TelephonyTest {
-    @Mock
-    private SmsStorageMonitor mSmsStorageMonitor;
-    @Mock
-    private android.telephony.SmsMessage mSmsMessage;
-    @Mock
-    private SmsMessage mGsmSmsMessage;
-
-    private GsmCellBroadcastHandler mGsmCellBroadcastHandler;
-
-    @Before
-    public void setUp() throws Exception {
-
-        super.setUp(getClass().getSimpleName());
-
-        doReturn(true).when(mTelephonyManager).getSmsReceiveCapableForPhone(anyInt(), anyBoolean());
-        doReturn(true).when(mSmsStorageMonitor).isStorageAvailable();
-
-        mGsmCellBroadcastHandler = GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(
-                mContext, mPhone);
-        monitorTestableLooper(
-                new TestableLooper(mGsmCellBroadcastHandler.getHandler().getLooper()));
-        processAllMessages();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mGsmCellBroadcastHandler = null;
-        super.tearDown();
-    }
-
-    @Test
-    @Ignore
-    public void testBroadcastSms() {
-        mContextFixture.putStringArrayResource(
-                com.android.internal.R.array.config_defaultCellBroadcastReceiverPkgs,
-                new String[]{"fake.cellbroadcastreceiver"});
-
-        Settings.Secure.putString(mContext.getContentResolver(),
-                CMAS_ADDITIONAL_BROADCAST_PKG, "another.fake.pkg");
-        mSimulatedCommands.notifyGsmBroadcastSms(new byte[] {
-                (byte)0xc0, //geographical scope
-                (byte)0x01, //serial number
-                (byte)0x01, //serial number
-                (byte)0x01, //message identifier
-                (byte)0x01, //message identifier
-                (byte)0x01
-        });
-        processAllMessages();
-        ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mContextFixture.getTestDouble(), times(2)).sendOrderedBroadcastAsUser(
-                intentArgumentCaptor.capture(), eq(UserHandle.ALL),
-                eq(Manifest.permission.RECEIVE_SMS), eq(AppOpsManager.OP_RECEIVE_SMS),
-                nullable(BroadcastReceiver.class), any(Handler.class), eq(Activity.RESULT_OK),
-                eq(null), eq(null));
-
-        List<Intent> intentList = intentArgumentCaptor.getAllValues();
-
-        assertEquals(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION,
-                intentList.get(0).getAction());
-        assertEquals("another.fake.pkg", intentList.get(0).getPackage());
-
-        assertEquals(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION,
-                intentList.get(1).getAction());
-        assertEquals("fake.cellbroadcastreceiver", intentList.get(1).getPackage());
-    }
-}
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..b99749c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -27,8 +27,8 @@
 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;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -42,7 +42,6 @@
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -806,9 +805,10 @@
         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),
-                eq((UserHandle)null), any(IntentFilter.class), eq((String)null), eq((Handler)null));
+        // implementation in ContextFixture. registerReceiver may be called more than once (for
+        // example by GsmInboundSmsHandler if TEST_MODE is true)
+        verify(mContext, atLeastOnce()).registerReceiver(any(BroadcastReceiver.class),
+                any(IntentFilter.class));
 
         // wait for ScanRawTableThread
         waitForMs(100);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsCbTest.java
deleted file mode 100644
index 8f61c21..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsCbTest.java
+++ /dev/null
@@ -1,791 +0,0 @@
-/*
- * Copyright (C) 2010 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.gsm;
-
-import android.telephony.Rlog;
-import android.telephony.SmsCbEtwsInfo;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.internal.telephony.uicc.IccUtils;
-
-import org.junit.Test;
-
-import java.util.Random;
-
-/**
- * Test cases for basic SmsCbMessage operations
- */
-public class GsmSmsCbTest extends AndroidTestCase {
-
-    private static final String TAG = "GsmSmsCbTest";
-
-    private static final SmsCbLocation sTestLocation = new SmsCbLocation("94040", 1234, 5678);
-
-    private SmsCbMessage createFromPdu(byte[] pdu) {
-        try {
-            SmsCbHeader header = new SmsCbHeader(pdu);
-            byte[][] pdus = new byte[1][];
-            pdus[0] = pdu;
-            return GsmSmsCbMessage.createSmsCbMessage(getContext(), header, sTestLocation, pdus,
-                    /* slotIndex */ 0);
-        } catch (IllegalArgumentException e) {
-            return null;
-        }
-    }
-
-    private void doTestGeographicalScopeValue(byte[] pdu, byte b, int expectedGs) {
-        pdu[0] = b;
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected geographical scope decoded", expectedGs, msg
-                .getGeographicalScope());
-    }
-
-    @Test @SmallTest
-    public void testCreateNullPdu() {
-        SmsCbMessage msg = createFromPdu(null);
-        assertNull("createFromPdu(byte[] with null pdu should return null", msg);
-    }
-
-    @Test @SmallTest
-    public void testCreateTooShortPdu() {
-        byte[] pdu = new byte[4];
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertNull("createFromPdu(byte[] with too short pdu should return null", msg);
-    }
-
-    @Test @SmallTest
-    public void testGetGeographicalScope() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41,
-                (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6,
-                (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70,
-                (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5,
-                (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69,
-                (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75,
-                (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69,
-                (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00
-        };
-
-        doTestGeographicalScopeValue(pdu, (byte)0x00,
-                SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE);
-        doTestGeographicalScopeValue(pdu, (byte)0x40, SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE);
-        doTestGeographicalScopeValue(pdu, (byte)0x80,
-                SmsCbMessage.GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE);
-        doTestGeographicalScopeValue(pdu, (byte)0xC0, SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE);
-    }
-
-    @Test @SmallTest
-    public void testGetGeographicalScopeUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40,
-
-                (byte)0x01,
-
-                (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
-                (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
-                (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
-                (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
-                (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
-                (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
-                (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
-                (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x34
-        };
-
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected geographical scope decoded",
-                SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE, msg.getGeographicalScope());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7Bit() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41,
-                (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6,
-                (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70,
-                (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5,
-                (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69,
-                (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75,
-                (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69,
-                (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A GSM default alphabet message with carriage return padding",
-                msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7BitUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40,
-
-                (byte)0x01,
-
-                (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
-                (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
-                (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
-                (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
-                (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
-                (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
-                (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
-                (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x34
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A GSM default alphabet message with carriage return padding",
-                msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7BitMultipageUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x01, (byte)0xC0, (byte)0x00, (byte)0x40,
-
-                (byte)0x02,
-
-                (byte)0xC6, (byte)0xB4, (byte)0x7C, (byte)0x4E, (byte)0x07, (byte)0xC1,
-                (byte)0xC3, (byte)0xE7, (byte)0xF2, (byte)0xAA, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A,
-                (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34,
-                (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x0A,
-
-                (byte)0xD3, (byte)0xF2, (byte)0xF8, (byte)0xED, (byte)0x26, (byte)0x83,
-                (byte)0xE0, (byte)0xE1, (byte)0x73, (byte)0xB9, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A,
-                (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34,
-                (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x0A
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected multipage 7-bit string decoded",
-                "First page+Second page",
-                msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7BitFull() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41,
-                (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6,
-                (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70,
-                (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5,
-                (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xC4, (byte)0xE5,
-                (byte)0xB4, (byte)0xFB, (byte)0x0C, (byte)0x2A, (byte)0xE3, (byte)0xC3, (byte)0x63,
-                (byte)0x3A, (byte)0x3B, (byte)0x0F, (byte)0xCA, (byte)0xCD, (byte)0x40, (byte)0x63,
-                (byte)0x74, (byte)0x58, (byte)0x1E, (byte)0x1E, (byte)0xD3, (byte)0xCB, (byte)0xF2,
-                (byte)0x39, (byte)0x88, (byte)0xFD, (byte)0x76, (byte)0x9F, (byte)0x59, (byte)0xA0,
-                (byte)0x76, (byte)0x39, (byte)0xEC, (byte)0x4E, (byte)0xBB, (byte)0xCF, (byte)0x20,
-                (byte)0x3A, (byte)0xBA, (byte)0x2C, (byte)0x2F, (byte)0x83, (byte)0xD2, (byte)0x73,
-                (byte)0x90, (byte)0xFB, (byte)0x0D, (byte)0x82, (byte)0x87, (byte)0xC9, (byte)0xE4,
-                (byte)0xB4, (byte)0xFB, (byte)0x1C, (byte)0x02
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals(
-                "Unexpected 7-bit string decoded",
-                "A GSM default alphabet message being exactly 93 characters long, " +
-                "meaning there is no padding!",
-                msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7BitFullUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40,
-
-                (byte)0x01,
-
-                (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
-                (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
-                (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
-                (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
-                (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xC4, (byte)0xE5, (byte)0xB4,
-                (byte)0xFB, (byte)0x0C, (byte)0x2A, (byte)0xE3, (byte)0xC3, (byte)0x63,
-                (byte)0x3A, (byte)0x3B, (byte)0x0F, (byte)0xCA, (byte)0xCD, (byte)0x40,
-                (byte)0x63, (byte)0x74, (byte)0x58, (byte)0x1E, (byte)0x1E, (byte)0xD3,
-                (byte)0xCB, (byte)0xF2, (byte)0x39, (byte)0x88, (byte)0xFD, (byte)0x76,
-                (byte)0x9F, (byte)0x59, (byte)0xA0, (byte)0x76, (byte)0x39, (byte)0xEC,
-                (byte)0x4E, (byte)0xBB, (byte)0xCF, (byte)0x20, (byte)0x3A, (byte)0xBA,
-                (byte)0x2C, (byte)0x2F, (byte)0x83, (byte)0xD2, (byte)0x73, (byte)0x90,
-                (byte)0xFB, (byte)0x0D, (byte)0x82, (byte)0x87, (byte)0xC9, (byte)0xE4,
-                (byte)0xB4, (byte)0xFB, (byte)0x1C, (byte)0x02,
-
-                (byte)0x52
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals(
-                "Unexpected 7-bit string decoded",
-                "A GSM default alphabet message being exactly 93 characters long, " +
-                "meaning there is no padding!",
-                msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7BitWithLanguage() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x04, (byte)0x11, (byte)0x41,
-                (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6,
-                (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70,
-                (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5,
-                (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69,
-                (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75,
-                (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69,
-                (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A GSM default alphabet message with carriage return padding",
-                msg.getMessageBody());
-
-        assertEquals("Unexpected language indicator decoded", "es", msg.getLanguageCode());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7BitWithLanguageInBody() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x10, (byte)0x11, (byte)0x73,
-                (byte)0x7B, (byte)0x23, (byte)0x08, (byte)0x3A, (byte)0x4E, (byte)0x9B, (byte)0x20,
-                (byte)0x72, (byte)0xD9, (byte)0x1C, (byte)0xAE, (byte)0xB3, (byte)0xE9, (byte)0xA0,
-                (byte)0x30, (byte)0x1B, (byte)0x8E, (byte)0x0E, (byte)0x8B, (byte)0xCB, (byte)0x74,
-                (byte)0x50, (byte)0xBB, (byte)0x3C, (byte)0x9F, (byte)0x87, (byte)0xCF, (byte)0x65,
-                (byte)0xD0, (byte)0x3D, (byte)0x4D, (byte)0x47, (byte)0x83, (byte)0xC6, (byte)0x61,
-                (byte)0xB9, (byte)0x3C, (byte)0x1D, (byte)0x3E, (byte)0x97, (byte)0x41, (byte)0xF2,
-                (byte)0x32, (byte)0xBD, (byte)0x2E, (byte)0x77, (byte)0x83, (byte)0xE0, (byte)0x61,
-                (byte)0x32, (byte)0x39, (byte)0xED, (byte)0x3E, (byte)0x37, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A GSM default alphabet message with carriage return padding",
-                msg.getMessageBody());
-
-        assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody7BitWithLanguageInBodyUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x10,
-
-                (byte)0x01,
-
-                (byte)0x73, (byte)0x7B, (byte)0x23, (byte)0x08, (byte)0x3A, (byte)0x4E,
-                (byte)0x9B, (byte)0x20, (byte)0x72, (byte)0xD9, (byte)0x1C, (byte)0xAE,
-                (byte)0xB3, (byte)0xE9, (byte)0xA0, (byte)0x30, (byte)0x1B, (byte)0x8E,
-                (byte)0x0E, (byte)0x8B, (byte)0xCB, (byte)0x74, (byte)0x50, (byte)0xBB,
-                (byte)0x3C, (byte)0x9F, (byte)0x87, (byte)0xCF, (byte)0x65, (byte)0xD0,
-                (byte)0x3D, (byte)0x4D, (byte)0x47, (byte)0x83, (byte)0xC6, (byte)0x61,
-                (byte)0xB9, (byte)0x3C, (byte)0x1D, (byte)0x3E, (byte)0x97, (byte)0x41,
-                (byte)0xF2, (byte)0x32, (byte)0xBD, (byte)0x2E, (byte)0x77, (byte)0x83,
-                (byte)0xE0, (byte)0x61, (byte)0x32, (byte)0x39, (byte)0xED, (byte)0x3E,
-                (byte)0x37, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x37
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A GSM default alphabet message with carriage return padding",
-                msg.getMessageBody());
-
-        assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBody8Bit() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x44, (byte)0x11, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45, (byte)0x46, (byte)0x47, (byte)0x41,
-                (byte)0x42, (byte)0x43, (byte)0x44, (byte)0x45
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("8-bit message body should be empty", "", msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBodyUcs2() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x48, (byte)0x11, (byte)0x00,
-                (byte)0x41, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x55, (byte)0x00, (byte)0x43,
-                (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x20, (byte)0x00,
-                (byte)0x6D, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73,
-                (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65, (byte)0x00,
-                (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x6E,
-                (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x69, (byte)0x00,
-                (byte)0x6E, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x67,
-                (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x20, (byte)0x04,
-                (byte)0x34, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68,
-                (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61, (byte)0x00,
-                (byte)0x63, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x72,
-                (byte)0x00, (byte)0x0D, (byte)0x00, (byte)0x0D
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A UCS2 message containing a \u0434 character", msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBodyUcs2Umts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x48,
-
-                (byte)0x01,
-
-                (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x55,
-                (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x32,
-                (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x6D, (byte)0x00, (byte)0x65,
-                (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x61,
-                (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x20,
-                (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x6E,
-                (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x69,
-                (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E,
-                (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x61,
-                (byte)0x00, (byte)0x20, (byte)0x04, (byte)0x34, (byte)0x00, (byte)0x20,
-                (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68, (byte)0x00, (byte)0x61,
-                (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x63,
-                (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x72,
-                (byte)0x00, (byte)0x0D, (byte)0x00, (byte)0x0D,
-
-                (byte)0x4E
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A UCS2 message containing a \u0434 character", msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBodyUcs2MultipageUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x48,
-
-                (byte)0x02,
-
-                (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x41,
-                (byte)0x00, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-
-                (byte)0x06,
-
-                (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x42,
-                (byte)0x00, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-                (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
-
-                (byte)0x06
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected multipage UCS2 string decoded",
-                "AAABBB", msg.getMessageBody());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBodyUcs2WithLanguageInBody() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x11, (byte)0x11, (byte)0x78,
-                (byte)0x3C, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x55,
-                (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x32, (byte)0x00,
-                (byte)0x20, (byte)0x00, (byte)0x6D, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x73,
-                (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x67, (byte)0x00,
-                (byte)0x65, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F,
-                (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, (byte)0x00,
-                (byte)0x69, (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E,
-                (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x61, (byte)0x00,
-                (byte)0x20, (byte)0x04, (byte)0x34, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63,
-                (byte)0x00, (byte)0x68, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x72, (byte)0x00,
-                (byte)0x61, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65,
-                (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x0D
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A UCS2 message containing a \u0434 character", msg.getMessageBody());
-
-        assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageBodyUcs2WithLanguageInBodyUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x11,
-
-                (byte)0x01,
-
-                (byte)0x78, (byte)0x3C, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20,
-                (byte)0x00, (byte)0x55, (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53,
-                (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x6D,
-                (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73,
-                (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65,
-                (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F,
-                (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61,
-                (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69,
-                (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20,
-                (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x20, (byte)0x04, (byte)0x34,
-                (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68,
-                (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61,
-                (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65,
-                (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x0D,
-
-                (byte)0x50
-        };
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected 7-bit string decoded",
-                "A UCS2 message containing a \u0434 character", msg.getMessageBody());
-
-        assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageIdentifier() {
-        byte[] pdu = {
-                (byte)0xC0, (byte)0x00, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41,
-                (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6,
-                (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70,
-                (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5,
-                (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69,
-                (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75,
-                (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69,
-                (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00
-        };
-
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected message identifier decoded", 12345, msg.getServiceCategory());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageIdentifierUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40,
-
-                (byte)0x01,
-
-                (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
-                (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
-                (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
-                (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
-                (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
-                (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
-                (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
-                (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x34
-        };
-
-        SmsCbMessage msg = createFromPdu(pdu);
-
-        assertEquals("Unexpected message identifier decoded", 12345, msg.getServiceCategory());
-    }
-
-    @Test @SmallTest
-    public void testGetMessageCode() {
-        byte[] pdu = {
-                (byte)0x2A, (byte)0xA5, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41,
-                (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6,
-                (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70,
-                (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5,
-                (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69,
-                (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75,
-                (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69,
-                (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00
-        };
-
-        SmsCbMessage msg = createFromPdu(pdu);
-        int messageCode = (msg.getSerialNumber() & 0x3ff0) >> 4;
-
-        assertEquals("Unexpected message code decoded", 682, messageCode);
-    }
-
-    @Test @SmallTest
-    public void testGetMessageCodeUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40,
-
-                (byte)0x01,
-
-                (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
-                (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
-                (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
-                (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
-                (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
-                (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
-                (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
-                (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x34
-        };
-
-        SmsCbMessage msg = createFromPdu(pdu);
-        int messageCode = (msg.getSerialNumber() & 0x3ff0) >> 4;
-
-        assertEquals("Unexpected message code decoded", 682, messageCode);
-    }
-
-    @Test @SmallTest
-    public void testGetUpdateNumber() {
-        byte[] pdu = {
-                (byte)0x2A, (byte)0xA5, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41,
-                (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91, (byte)0xCB, (byte)0xE6,
-                (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07, (byte)0x85, (byte)0xD9, (byte)0x70,
-                (byte)0x74, (byte)0x58, (byte)0x5C, (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5,
-                (byte)0xF9, (byte)0x3C, (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69,
-                (byte)0x3A, (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9, (byte)0x75,
-                (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93, (byte)0xC9, (byte)0x69,
-                (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00
-        };
-
-        SmsCbMessage msg = createFromPdu(pdu);
-        int updateNumber = msg.getSerialNumber() & 0x000f;
-
-        assertEquals("Unexpected update number decoded", 5, updateNumber);
-    }
-
-    @Test @SmallTest
-    public void testGetUpdateNumberUmts() {
-        byte[] pdu = {
-                (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40,
-
-                (byte)0x01,
-
-                (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
-                (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
-                (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
-                (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
-                (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
-                (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
-                (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
-                (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
-                (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
-                (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
-                (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
-                (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
-                (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
-                (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
-
-                (byte)0x34
-        };
-
-        SmsCbMessage msg = createFromPdu(pdu);
-        int updateNumber = msg.getSerialNumber() & 0x000f;
-
-        assertEquals("Unexpected update number decoded", 5, updateNumber);
-    }
-
-    /* ETWS Test message including header */
-    private static final byte[] etwsMessageNormal = IccUtils.hexStringToBytes("000011001101" +
-            "0D0A5BAE57CE770C531790E85C716CBF3044573065B930675730" +
-            "9707767A751F30025F37304463FA308C306B5099304830664E0B30553044FF086C178C615E81FF09" +
-            "0000000000000000000000000000");
-
-    private static final byte[] etwsMessageCancel = IccUtils.hexStringToBytes("000011001101" +
-            "0D0A5148307B3069002800310030003A0035" +
-            "00320029306E7DCA602557309707901F5831309253D66D883057307E3059FF086C178C615E81FF09" +
-            "00000000000000000000000000000000000000000000");
-
-    private static final byte[] etwsMessageTest = IccUtils.hexStringToBytes("000011031101" +
-            "0D0A5BAE57CE770C531790E85C716CBF3044" +
-            "573065B9306757309707300263FA308C306B5099304830664E0B30553044FF086C178C615E81FF09" +
-            "00000000000000000000000000000000000000000000");
-
-    // FIXME: add example of ETWS primary notification PDU
-
-    @Test @SmallTest
-    public void testEtwsMessageNormal() {
-        SmsCbMessage msg = createFromPdu(etwsMessageNormal);
-        Rlog.d(TAG, msg.toString());
-        assertEquals("GS mismatch", 0, msg.getGeographicalScope());
-        assertEquals("serial number mismatch", 0, msg.getSerialNumber());
-        assertEquals("message ID mismatch", 0x1100, msg.getServiceCategory());
-        assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE,
-                msg.getEtwsWarningInfo().getWarningType());
-    }
-
-    @Test @SmallTest
-    public void testEtwsMessageCancel() {
-        SmsCbMessage msg = createFromPdu(etwsMessageCancel);
-        Rlog.d(TAG, msg.toString());
-        assertEquals("GS mismatch", 0, msg.getGeographicalScope());
-        assertEquals("serial number mismatch", 0, msg.getSerialNumber());
-        assertEquals("message ID mismatch", 0x1100, msg.getServiceCategory());
-        assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE,
-                msg.getEtwsWarningInfo().getWarningType());
-    }
-
-    @Test @SmallTest
-    public void testEtwsMessageTest() {
-        SmsCbMessage msg = createFromPdu(etwsMessageTest);
-        Rlog.d(TAG, msg.toString());
-        assertEquals("GS mismatch", 0, msg.getGeographicalScope());
-        assertEquals("serial number mismatch", 0, msg.getSerialNumber());
-        assertEquals("message ID mismatch", 0x1103, msg.getServiceCategory());
-        assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE,
-                msg.getEtwsWarningInfo().getWarningType());
-    }
-
-    // Make sure we don't throw an exception if we feed random data to the PDU parser.
-    @Test @SmallTest
-    public void testRandomPdus() {
-        Random r = new Random(94040);
-        for (int run = 0; run < 10000; run++) {
-            int len = r.nextInt(140);
-            byte[] data = new byte[len];
-            for (int i = 0; i < len; i++) {
-                data[i] = (byte) r.nextInt(256);
-            }
-            try {
-                // this should return a SmsCbMessage object or null for invalid data
-                SmsCbMessage msg = createFromPdu(data);
-            } catch (Exception e) {
-                Rlog.d(TAG, "exception thrown", e);
-                fail("Exception in decoder at run " + run + " length " + len + ": " + e);
-            }
-        }
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken
index c599ad0..a9d869c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken
@@ -20,7 +20,7 @@
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemClock;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 
 import com.android.internal.telephony.BaseCommands;
 import com.android.internal.telephony.UUSInfo;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken
index f32e4bd..9fbb86c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken
@@ -18,7 +18,7 @@
 
 import android.os.HandlerThread;
 import android.test.AndroidTestCase;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
 
 import java.nio.charset.Charset;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/FeatureConnectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/FeatureConnectorTest.java
index a544bc3..a2b4de8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/FeatureConnectorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/FeatureConnectorTest.java
@@ -19,11 +19,13 @@
 import junit.framework.AssertionFailedError;
 
 import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.pm.PackageManager;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.telephony.ims.feature.ImsFeature;
@@ -70,7 +72,7 @@
         mHandlerThread = new HandlerThread("ConnectorHandlerThread");
         mHandlerThread.start();
 
-        mFeatureConnector = new FeatureConnector<ImsManager>(mContext, phoneId,
+        mFeatureConnector = new FeatureConnector<>(mContext, phoneId,
             mListener, mExecutor, mHandlerThread.getLooper());
         mFeatureConnector.mListener = mListener;
     }
@@ -85,7 +87,7 @@
     @SmallTest
     public void testConnect() {
         // ImsManager is supported on device
-        when(mListener.isSupported()).thenReturn(true);
+        setImsSupportedFeature(true);
         when(mListener.getFeatureManager()).thenReturn(mImsManager);
 
         mFeatureConnector.connect();
@@ -97,7 +99,7 @@
         reset(mListener);
 
         // ImsManager is NOT supported on device
-        when(mListener.isSupported()).thenReturn(false);
+        setImsSupportedFeature(false);
         when(mListener.getFeatureManager()).thenReturn(mImsManager);
 
         mFeatureConnector.connect();
@@ -145,4 +147,9 @@
         // Verify removeNotifyStatusChangedCallback will be called if ImsManager is not null.
         verify(mImsManager).removeNotifyStatusChangedCallback(anyObject());
     }
+
+    private void setImsSupportedFeature(boolean isSupported) {
+        doReturn(isSupported).when(mPackageManager).hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_IMS);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
index 38218c4..f09140e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.doReturn;
@@ -95,8 +96,8 @@
         doReturn(mSubscriptionController).when(mBinder).queryLocalInterface(anyString());
         mServiceManagerMockedServices.put("isub", mBinder);
         // Stick to the CarrierConfig defaults unless explicitly overwritten.
-        doReturn("-1").when(mSubscriptionController)
-                .getSubscriptionProperty(anyInt(), anyString(), anyString());
+        doReturn("-1").when(mSubscriptionController).getSubscriptionProperty(anyInt(), anyString(),
+                anyString(), nullable(String.class));
 
 
         doReturn(true).when(mMmTelFeatureConnection).isBinderAlive();
@@ -133,6 +134,8 @@
         mBundle.putBoolean(
                 CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL,
                 WFC_NOT_USE_HOME_MODE_FOR_ROAMING_VAL);
+        mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL, true);
+
     }
 
     @Test @SmallTest
@@ -143,38 +146,44 @@
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         assertEquals(WFC_IMS_ROAMING_ENABLE_DEFAULT_VAL, imsManager.isWfcRoamingEnabledByUser());
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         assertEquals(ENHANCED_4G_MODE_DEFAULT_VAL,
                 imsManager.isEnhanced4gLteModeSettingEnabledByUser());
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.ENHANCED_4G_MODE_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         assertEquals(WFC_IMS_MODE_DEFAULT_VAL, imsManager.getWfcMode(false));
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         assertEquals(WFC_IMS_ROAMING_MODE_DEFAULT_VAL, imsManager.getWfcMode(true));
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         assertEquals(VT_IMS_ENABLE_DEFAULT_VAL, imsManager.isVtEnabledByUser());
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.VT_IMS_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
     }
 
     @Test @SmallTest
@@ -243,6 +252,10 @@
         assertEquals(true, imsManager.isVolteProvisionedOnDevice());
         verify(mImsConfigImplBaseMock, times(1)).getConfigInt(
                 eq(ImsConfig.ConfigConstants.VLT_SETTING_ENABLED));
+
+        assertEquals(true, imsManager.isEabProvisionedOnDevice());
+        verify(mImsConfigImplBaseMock, times(1)).getConfigInt(
+                eq(ImsConfig.ConfigConstants.EAB_SETTING_ENABLED));
     }
 
     @Test
@@ -267,7 +280,30 @@
                 eq(0));
         verify(mImsConfigImplBaseMock, times(1)).getConfigInt(
                 eq(ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED));
+    }
 
+    @Test
+    public void testEabSetProvisionedValues() throws Exception {
+        ImsManager imsManager = getImsManagerAndInitProvisionedValues();
+
+        assertEquals(true, imsManager.isEabProvisionedOnDevice());
+        verify(mImsConfigImplBaseMock, times(1)).getConfigInt(
+                eq(ImsConfig.ConfigConstants.EAB_SETTING_ENABLED));
+
+        imsManager.getConfigInterface().setProvisionedValue(
+                ImsConfig.ConfigConstants.EAB_SETTING_ENABLED,
+                ImsConfig.FeatureValueConstants.OFF);
+
+        assertEquals(0, (int) mProvisionedIntVals.get(
+                ImsConfig.ConfigConstants.EAB_SETTING_ENABLED));
+
+        assertEquals(false, imsManager.isEabProvisionedOnDevice());
+
+        verify(mImsConfigImplBaseMock, times(1)).setConfig(
+                eq(ImsConfig.ConfigConstants.EAB_SETTING_ENABLED),
+                eq(0));
+        verify(mImsConfigImplBaseMock, times(1)).getConfigInt(
+                eq(ImsConfig.ConfigConstants.EAB_SETTING_ENABLED));
     }
 
     /**
@@ -285,12 +321,14 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                         anyInt(),
                         eq(SubscriptionManager.WFC_IMS_MODE),
-                        anyString());
+                        anyString(),
+                        nullable(String.class));
         doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED))
                 .when(mSubscriptionController).getSubscriptionProperty(
                         anyInt(),
                         eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
-                        anyString());
+                        anyString(),
+                        nullable(String.class));
         ImsManager imsManager = getImsManagerAndInitProvisionedValues();
 
         // Roaming
@@ -345,7 +383,8 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         ImsManager imsManager = getImsManagerAndInitProvisionedValues();
 
@@ -380,7 +419,8 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         ImsManager imsManager = getImsManagerAndInitProvisionedValues();
 
@@ -454,7 +494,8 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         // The device is roaming
         doReturn(true).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
@@ -500,7 +541,8 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         // The device is roaming
         doReturn(true).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
@@ -534,13 +576,15 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
         // The user has enabled the "WFC while roaming" setting in the UI while WFC was enabled
         doReturn(String.valueOf(1 /*true*/))
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         ImsManager imsManager = getImsManagerAndInitProvisionedValues();
 
@@ -574,7 +618,8 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_ENABLED),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         ImsManager imsManager = getImsManagerAndInitProvisionedValues();
 
@@ -609,12 +654,14 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
         doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY))
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
         ImsManager imsManager = getImsManagerAndInitProvisionedValues();
 
         // Roaming
@@ -687,12 +734,14 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
         doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED))
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         ImsManager imsManager = getImsManagerAndInitProvisionedValues();
 
@@ -702,7 +751,8 @@
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         // Set WFC roaming network mode to not editable.
         mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL,
@@ -713,7 +763,8 @@
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
     }
 
     /**
@@ -730,12 +781,14 @@
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
         doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED))
                 .when(mSubscriptionController).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         // Set to use WFC home network mode in roaming network.
         mBundle.putBoolean(
@@ -749,7 +802,8 @@
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
 
         // Set WFC home network mode to not editable.
         mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL,
@@ -760,7 +814,8 @@
         verify(mSubscriptionController, times(1)).getSubscriptionProperty(
                 anyInt(),
                 eq(SubscriptionManager.WFC_IMS_MODE),
-                anyString());
+                anyString(),
+                nullable(String.class));
     }
 
     /**
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
index 30baabb..2e1c3eb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
@@ -54,6 +54,9 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.util.ArraySet;
+
+import com.android.internal.telephony.PhoneConfigurationManager;
 
 import org.junit.After;
 import org.junit.Before;
@@ -78,11 +81,15 @@
 
     private static final ComponentName TEST_DEVICE_DEFAULT_NAME = new ComponentName("TestDevicePkg",
             "DeviceImsService");
+    private static final ComponentName TEST_DEVICE2_DEFAULT_NAME = new ComponentName(
+            "TestDevicePkg2", "DeviceImsService2");
     private static final ComponentName TEST_CARRIER_DEFAULT_NAME = new ComponentName(
             "TestCarrierPkg", "CarrierImsService");
     private static final ComponentName TEST_CARRIER_2_DEFAULT_NAME = new ComponentName(
             "TestCarrier2Pkg", "Carrier2ImsService");
 
+    private static final int NUM_MAX_SLOTS = 2;
+
     @Mock
     Context mMockContext;
     @Mock
@@ -127,7 +134,8 @@
     @Test
     @SmallTest
     public void testAddDevicePackageToCache() {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         HashSet<String> features = new HashSet<>();
         features.add(ImsResolver.METADATA_EMERGENCY_MMTEL_FEATURE);
         features.add(ImsResolver.METADATA_MMTEL_FEATURE);
@@ -152,12 +160,13 @@
     @Test
     @SmallTest
     public void testAddCarrierPackageToCache() {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         HashSet<String> features = new HashSet<>();
         features.add(ImsResolver.METADATA_EMERGENCY_MMTEL_FEATURE);
         features.add(ImsResolver.METADATA_MMTEL_FEATURE);
         features.add(ImsResolver.METADATA_RCS_FEATURE);
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         setupPackageQuery(TEST_CARRIER_DEFAULT_NAME, features, true);
         setupController();
 
@@ -181,13 +190,14 @@
     @Test
     @SmallTest
     public void testCarrierPackageBind() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         // Setup the carrier features
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> features = new HashSet<>();
         features.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_MMTEL));
         features.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
         // Set CarrierConfig default package name and make it available as the CarrierConfig.
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         setupPackageQuery(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true);
         ImsServiceController controller = setupController();
 
@@ -202,16 +212,127 @@
     }
 
     /**
+     * Set the carrier config override value to many separate services for MMTEL and RCS and ensure
+     * that ImsResolver calls .bind on those package names with the correct ImsFeatures.
+     */
+    @Test
+    @SmallTest
+    public void testDeviceCarrierPackageBindMultipleServices() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        // Setup the carrier features: carrier 1 - MMTEL, slot 0; carrier 2 RCS, slot 0
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featuresMmTel = new HashSet<>();
+        featuresMmTel.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_MMTEL));
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featuresRcs = new HashSet<>();
+        featuresRcs.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featuresAll = new HashSet<>(featuresMmTel);
+        featuresAll.addAll(featuresRcs);
+        // Setup the device features: MMTEL, RCS on slot 0,1
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featuresDevice = new HashSet<>();
+        featuresDevice.add(new ImsFeatureConfiguration.FeatureSlotPair(1,
+                ImsFeature.FEATURE_MMTEL));
+        featuresDevice.add(new ImsFeatureConfiguration.FeatureSlotPair(1, ImsFeature.FEATURE_RCS));
+        // Set CarrierConfig default package name and make it available as the CarrierConfig.
+        setConfigCarrierStringMmTel(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringRcs(0, TEST_CARRIER_2_DEFAULT_NAME.getPackageName());
+        Set<String> deviceFeatures = new ArraySet<>();
+        deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
+        List<ResolveInfo> info = new ArrayList<>();
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, deviceFeatures, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        info.add(getResolveInfo(TEST_CARRIER_2_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController deviceController = mock(ImsServiceController.class);
+        ImsServiceController carrierController1 = mock(ImsServiceController.class);
+        ImsServiceController carrierController2 = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController, carrierController1, carrierController2);
+
+        // Start bind to carrier service
+        startBindCarrierConfigAlreadySet();
+        // setup features response
+        // emulate mMockQueryManager returning information about pending queries.
+        when(mMockQueryManager.isQueryInProgress()).thenReturn(true);
+        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, featuresAll, 1);
+        when(mMockQueryManager.isQueryInProgress()).thenReturn(false);
+        setupDynamicQueryFeatures(TEST_CARRIER_2_DEFAULT_NAME, featuresAll, 1);
+
+        verify(deviceController).bind(featuresDevice);
+        verify(deviceController, never()).unbind();
+        verify(carrierController1).bind(featuresMmTel);
+        verify(carrierController1, never()).unbind();
+        verify(carrierController2).bind(featuresRcs);
+        verify(carrierController2, never()).unbind();
+        assertEquals(TEST_CARRIER_DEFAULT_NAME, carrierController1.getComponentName());
+        assertEquals(TEST_CARRIER_2_DEFAULT_NAME, carrierController2.getComponentName());
+    }
+
+    /**
+     * Set the carrier config override value to two separate services for MMTEL and RCS and ensure
+     * that ImsResolver calls .bind on those package names with the correct ImsFeatures.
+     */
+    @Test
+    @SmallTest
+    public void testCarrierPackageBindOneConfigTwoSupport() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        // Setup the carrier features
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featuresMmTel = new HashSet<>();
+        featuresMmTel.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_MMTEL));
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featuresRcs = new HashSet<>();
+        featuresRcs.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
+        featuresRcs.add(new ImsFeatureConfiguration.FeatureSlotPair(1, ImsFeature.FEATURE_RCS));
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> allFeatures = new HashSet<>(featuresMmTel);
+        allFeatures.addAll(featuresRcs);
+        // Set CarrierConfig default package name and make it available as the CarrierConfig.
+        setConfigCarrierStringMmTel(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        // TEST_CARRIER_DEFAULT_NAME isnt configured for MMTEL on slot 1.
+        featuresMmTel.remove(new ImsFeatureConfiguration.FeatureSlotPair(1,
+                ImsFeature.FEATURE_MMTEL));
+        setConfigCarrierStringRcs(0, TEST_CARRIER_2_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringRcs(1, TEST_CARRIER_2_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        info.add(getResolveInfo(TEST_CARRIER_2_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController deviceController = mock(ImsServiceController.class);
+        ImsServiceController carrierController1 = mock(ImsServiceController.class);
+        ImsServiceController carrierController2 = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController, carrierController1, carrierController2);
+
+        // Start bind to carrier service
+        startBindCarrierConfigAlreadySet();
+        // setup features response
+        // emulate mMockQueryManager returning information about pending queries.
+        when(mMockQueryManager.isQueryInProgress()).thenReturn(true);
+        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, allFeatures, 1);
+        when(mMockQueryManager.isQueryInProgress()).thenReturn(false);
+        setupDynamicQueryFeatures(TEST_CARRIER_2_DEFAULT_NAME, allFeatures, 1);
+
+        verify(deviceController, never()).bind(any());
+        verify(deviceController, never()).unbind();
+        verify(carrierController1).bind(featuresMmTel);
+        verify(carrierController1, never()).unbind();
+        verify(carrierController2).bind(featuresRcs);
+        verify(carrierController2, never()).unbind();
+        assertEquals(TEST_CARRIER_DEFAULT_NAME, carrierController1.getComponentName());
+        assertEquals(TEST_CARRIER_2_DEFAULT_NAME, carrierController2.getComponentName());
+    }
+
+    /**
      * Creates a carrier ImsService that defines FEATURE_EMERGENCY_MMTEL and ensure that the
      * controller sets this capability.
      */
     @Test
     @SmallTest
     public void testCarrierPackageBindWithEmergencyCalling() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         // Set CarrierConfig default package name and make it available to the package manager
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> features = new HashSet<>();
+        features.add(new ImsFeatureConfiguration.FeatureSlotPair(0,
+                ImsFeature.FEATURE_EMERGENCY_MMTEL));
         features.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_MMTEL));
         features.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
         setupPackageQuery(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true);
@@ -226,15 +347,45 @@
     }
 
     /**
+     * Creates a carrier ImsService that defines FEATURE_EMERGENCY_MMTEL but not FEATURE_MMTEL and
+     * ensure that the controller doesn't set FEATURE_EMERGENCY_MMTEL.
+     */
+    @Test
+    @SmallTest
+    public void testCarrierPackageBindWithEmergencyButNotMmtel() throws RemoteException {
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        // Set CarrierConfig default package name and make it available to the package manager
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> features = new HashSet<>();
+        features.add(new ImsFeatureConfiguration.FeatureSlotPair(0,
+                ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        features.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
+        setupPackageQuery(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true);
+        ImsServiceController controller = setupController();
+
+        startBindCarrierConfigAlreadySet();
+        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, features, 1);
+
+        // We will not bind with FEATURE_EMERGENCY_MMTEL
+        features.remove(new ImsFeatureConfiguration.FeatureSlotPair(0,
+                ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        verify(controller).bind(features);
+        verify(controller, never()).unbind();
+        assertEquals(TEST_CARRIER_DEFAULT_NAME, controller.getComponentName());
+    }
+
+    /**
      * Creates a carrier ImsService that does not report FEATURE_EMERGENCY_MMTEL and then update the
      * ImsService to define it. Ensure that the controller sets this capability once enabled.
      */
     @Test
     @SmallTest
     public void testCarrierPackageChangeEmergencyCalling() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         // Set CarrierConfig default package name and make it available to the package manager
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> features = new HashSet<>();
         features.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_MMTEL));
         setupPackageQuery(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true);
@@ -266,13 +417,14 @@
     @Test
     @SmallTest
     public void testDontBindWhenNullCarrierPackage() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         setupPackageQuery(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true);
         ImsServiceController controller = setupController();
 
         // Set the CarrierConfig string to null so that ImsResolver will not bind to the available
         // Services
-        setConfigCarrierString(0, null);
+        setConfigCarrierStringMmTelRcs(0, null);
         startBindCarrierConfigAlreadySet();
 
         mLooper.processAllMessages();
@@ -288,7 +440,8 @@
     @Test
     @SmallTest
     public void testDevicePackageBind() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> features = new HashSet<>();
         features.add(ImsResolver.METADATA_MMTEL_FEATURE);
@@ -313,6 +466,244 @@
     }
 
     /**
+     * Test that the ImsService corresponding to the default device ImsService package name is
+     * bound and when there is a configuration change from two SIMs to one, the features are
+     * updated correctly.
+     */
+    @Test
+    @SmallTest
+    public void testDevicePackageBind_MsimToOneSim() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features = new HashSet<>();
+        features.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        features.add(ImsResolver.METADATA_RCS_FEATURE);
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, features, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController controller = setupController();
+
+
+        startBindNoCarrierConfig(1);
+        mLooper.processAllMessages();
+
+        // There is no carrier override set, so make sure that the ImsServiceController binds
+        // to all SIMs.
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet = convertToHashSet(features, 0);
+        featureSet.addAll(convertToHashSet(features, 1));
+        verify(controller).bind(featureSet);
+        verify(controller, never()).unbind();
+        verify(mMockQueryManager, never()).startQuery(any(), any());
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, controller.getComponentName());
+
+        // Change number of SIMs and verify the features in the ImsServiceController are changed
+        // as well
+        PhoneConfigurationManager.notifyMultiSimConfigChange(1);
+        mLooper.processAllMessages();
+        featureSet = convertToHashSet(features, 0);
+        verify(controller).changeImsServiceFeatures(featureSet);
+        verify(controller, never()).unbind();
+    }
+
+    /**
+     * Test that the ImsService corresponding to the default device ImsService package name is
+     * bound and when there is a configuration change from one to two SIMs, the features are
+     * updated correctly.
+     */
+    @Test
+    @SmallTest
+    public void testDevicePackageBind_OneSimToMsim() throws RemoteException {
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features = new HashSet<>();
+        features.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        features.add(ImsResolver.METADATA_RCS_FEATURE);
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, features, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController controller = setupController();
+
+
+        startBindNoCarrierConfig(1);
+        mLooper.processAllMessages();
+
+        // There is no carrier override set, so make sure that the ImsServiceController binds
+        // to all SIMs.
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet = convertToHashSet(features, 0);
+        verify(controller).bind(featureSet);
+        verify(controller, never()).unbind();
+        verify(mMockQueryManager, never()).startQuery(any(), any());
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, controller.getComponentName());
+
+        // Change number of SIMs and verify the features in the ImsServiceController are changed
+        // as well
+        PhoneConfigurationManager.notifyMultiSimConfigChange(2);
+        // Carrier config changed should happen for slot 1 (independent of carrier ImsService)
+        sendCarrierConfigChanged(1, 1);
+        featureSet.addAll(convertToHashSet(features, 1));
+        verify(controller).changeImsServiceFeatures(featureSet);
+        verify(controller, never()).unbind();
+    }
+
+    /**
+     * Test that when a device and carrier override package are set, both ImsServices are bound.
+     * Verify that the carrier ImsService features are created and the device default features
+     * are created for all features that are not covered by the carrier ImsService. When the device
+     * configuration is changed from one SIM to MSIM, ensure that the capabilities are reflected.
+     */
+    @Test
+    @SmallTest
+    public void testDeviceAndCarrierPackageBind_OneSimToMsim() throws RemoteException {
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        // set device features to MMTEL, RCS
+        Set<String> deviceFeatures = new HashSet<>();
+        deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
+        // Set the carrier override package for slot 0
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
+        // Carrier service only supports RCS on slot 0
+        carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, deviceFeatures, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        // Only return info if not using the compat argument
+        setupPackageQuery(info);
+        ImsServiceController deviceController = mock(ImsServiceController.class);
+        ImsServiceController carrierController = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController, carrierController);
+
+        startBindCarrierConfigAlreadySet();
+        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);
+
+        // Verify that all features that have been defined for the carrier override are bound
+        verify(carrierController).bind(carrierFeatures);
+        verify(carrierController, never()).unbind();
+        assertEquals(TEST_CARRIER_DEFAULT_NAME, carrierController.getComponentName());
+        // Verify that all features that are not defined in the carrier override are bound in the
+        // device controller (including emergency voice for slot 0)
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatureSet =
+                convertToHashSet(deviceFeatures, 0);
+        deviceFeatureSet.removeAll(carrierFeatures);
+        verify(deviceController).bind(deviceFeatureSet);
+        verify(deviceController, never()).unbind();
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController.getComponentName());
+
+        // Move to MSIM and verify the features in the ImsServiceController are changed as well
+        PhoneConfigurationManager.notifyMultiSimConfigChange(2);
+        setConfigCarrierStringMmTelRcs(1, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, ImsFeature.FEATURE_RCS));
+        // Assume that there is a CarrierConfig change that kicks off query to carrier service.
+        sendCarrierConfigChanged(1, 1);
+        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2);
+        verify(carrierController).changeImsServiceFeatures(carrierFeatures);
+        deviceFeatureSet = convertToHashSet(deviceFeatures, 0);
+        deviceFeatureSet.addAll(convertToHashSet(deviceFeatures, 1));
+        deviceFeatureSet.removeAll(carrierFeatures);
+        verify(deviceController).changeImsServiceFeatures(deviceFeatureSet);
+        verify(deviceController, never()).unbind();
+    }
+
+    /**
+     * Test that when a device and carrier override package are set, both ImsServices are bound.
+     * Verify that the carrier ImsService features are created and the device default features
+     * are created for all features that are not covered by the carrier ImsService. When the device
+     * configuration is changed from one SIM to MSIM, ensure that the capabilities are reflected.
+     */
+    @Test
+    @SmallTest
+    public void testDeviceAndCarrierPackageBind_MsimToOneSim() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        // set device features to MMTEL, RCS
+        Set<String> deviceFeatures = new HashSet<>();
+        deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
+        // Set the carrier override package for slot 0, slot 1 as RCS
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(1, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
+        carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
+        carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, ImsFeature.FEATURE_RCS));
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, deviceFeatures, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        // Only return info if not using the compat argument
+        setupPackageQuery(info);
+        ImsServiceController deviceController = mock(ImsServiceController.class);
+        ImsServiceController carrierController = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController, carrierController);
+
+        startBindCarrierConfigAlreadySet();
+        setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);
+
+        // Verify that all features that have been defined for the carrier override are bound
+        verify(carrierController).bind(carrierFeatures);
+        verify(carrierController, never()).unbind();
+        assertEquals(TEST_CARRIER_DEFAULT_NAME, carrierController.getComponentName());
+        // Verify that all features that are not defined in the carrier override are bound in the
+        // device controller (including emergency voice for slot 0)
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatureSet =
+                convertToHashSet(deviceFeatures, 0);
+        deviceFeatureSet.addAll(convertToHashSet(deviceFeatures, 1));
+        deviceFeatureSet.removeAll(carrierFeatures);
+        verify(deviceController).bind(deviceFeatureSet);
+        verify(deviceController, never()).unbind();
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController.getComponentName());
+
+        // Move to single SIM and verify the features in the ImsServiceController are changed as
+        // well.
+        PhoneConfigurationManager.notifyMultiSimConfigChange(1);
+        mLooper.processAllMessages();
+        carrierFeatures = new HashSet<>();
+        carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
+        verify(carrierController).changeImsServiceFeatures(carrierFeatures);
+        deviceFeatureSet = convertToHashSet(deviceFeatures, 0);
+        deviceFeatureSet.removeAll(carrierFeatures);
+        verify(deviceController).changeImsServiceFeatures(deviceFeatureSet);
+        verify(deviceController, never()).unbind();
+    }
+
+    /**
+     * Test that the ImsService corresponding to the default device ImsService package name is
+     * bound to only RCS if METADATA_EMERGENCY_MMTEL_FEATURE but not METADATA_MMTEL_FEATURE.
+     */
+    @Test
+    @SmallTest
+    public void testDevicePackageInvalidMmTelBind() throws RemoteException {
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features = new HashSet<>();
+        features.add(ImsResolver.METADATA_EMERGENCY_MMTEL_FEATURE);
+        features.add(ImsResolver.METADATA_RCS_FEATURE);
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, features, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController controller = setupController();
+
+
+        startBindNoCarrierConfig(1);
+        mLooper.processAllMessages();
+
+        // There is no carrier override set, so make sure that the ImsServiceController binds
+        // to all SIMs.
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet = convertToHashSet(features, 0);
+        verify(controller).bind(featureSet);
+        verify(controller, never()).unbind();
+        verify(mMockQueryManager, never()).startQuery(any(), any());
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, controller.getComponentName());
+    }
+
+    /**
      * Test that when a device and carrier override package are set, both ImsServices are bound.
      * Verify that the carrier ImsService features are created and the device default features
      * are created for all features that are not covered by the carrier ImsService.
@@ -320,13 +711,14 @@
     @Test
     @SmallTest
     public void testDeviceAndCarrierPackageBind() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
@@ -363,7 +755,8 @@
     @Test
     @SmallTest
     public void testGetDeviceCarrierFeatures() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         ImsServiceController deviceController = mock(ImsServiceController.class);
         ImsServiceController carrierController = mock(ImsServiceController.class);
 
@@ -392,7 +785,8 @@
     @Test
     @SmallTest
     public void testAddDeviceFeatureNoCarrier() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> features = new HashSet<>();
         features.add(ImsResolver.METADATA_MMTEL_FEATURE);
@@ -423,18 +817,100 @@
     }
 
     /**
+     * Bind to device ImsServices and change the feature set to include one that is not configured.
+     * Ensure it is not added.
+     */
+    @Test
+    @SmallTest
+    public void testMultipleDeviceAddFeatureNoCarrier() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE2_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> featuresController1 = new HashSet<>();
+        featuresController1.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        Set<String> featuresController2 = new HashSet<>();
+        featuresController2.add(ImsResolver.METADATA_RCS_FEATURE);
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, featuresController1, true));
+        info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, featuresController2, true));
+        setupPackageQuery(info);
+        ImsServiceController deviceController1 = mock(ImsServiceController.class);
+        ImsServiceController deviceController2 = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController1, deviceController2, null, null);
+        // Bind using default features
+        startBindNoCarrierConfig(2);
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet1 =
+                convertToHashSet(featuresController1, 0);
+        featureSet1.addAll(convertToHashSet(featuresController1, 1));
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet2 =
+                convertToHashSet(featuresController2, 0);
+        featureSet2.addAll(convertToHashSet(featuresController2, 1));
+        verify(deviceController1).bind(featureSet1);
+        verify(deviceController2).bind(featureSet2);
+
+        // add RCS to features list for device 1
+        Set<String> newFeatures1 = new HashSet<>(featuresController1);
+        newFeatures1.add(ImsResolver.METADATA_RCS_FEATURE);
+        info.clear();
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, newFeatures1, true));
+
+        packageChanged(TEST_DEVICE_DEFAULT_NAME.getPackageName());
+
+        // verify the devices have not changed features (because their configurations are still
+        // the same)
+        verify(deviceController1, times(2)).changeImsServiceFeatures(featureSet1);
+        verify(deviceController2, times(2)).changeImsServiceFeatures(featureSet2);
+    }
+
+    /**
+     * Bind to device ImsService and change the feature set while not supporting that configuration.
+     * Verify that changeImsServiceFeature is called with the original feature set.
+     */
+    @Test
+    @SmallTest
+    public void testAddDeviceFeatureNoCarrierRcsNotSupported() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(), "");
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features = new HashSet<>();
+        features.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        // Doesn't include RCS feature by default
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, features, true));
+        setupPackageQuery(info);
+        ImsServiceController controller = setupController();
+        // Bind using default features
+        startBindNoCarrierConfig(2);
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet =
+                convertToHashSet(features, 0);
+        featureSet.addAll(convertToHashSet(features, 1));
+        verify(controller).bind(featureSet);
+
+        // add RCS to features list
+        Set<String> newFeatures = new HashSet<>(features);
+        newFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
+        info.clear();
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, newFeatures, true));
+
+        packageChanged(TEST_DEVICE_DEFAULT_NAME.getPackageName());
+
+        // Verify new feature is not added to the device default, since it is not configured.
+        // This happens twice because two CarrierConfigChanged events occur, causing a
+        // changeImsServiceFeatures after bind() and then another after packageChanged.
+        verify(controller, times(2)).changeImsServiceFeatures(featureSet);
+    }
+
+    /**
      * Bind to device ImsService and change the feature set. Verify that changeImsServiceFeature
      * is called with the new feature set on the sub that doesn't include the carrier override.
      */
     @Test
     @SmallTest
     public void testAddDeviceFeatureWithCarrier() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the emergency voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0,
@@ -484,34 +960,43 @@
         // remove carrier overrides for slot 0
         newDeviceFeatureSet.removeAll(carrierFeatures);
         verify(deviceController).changeImsServiceFeatures(newDeviceFeatureSet);
-        verify(carrierController, never()).changeImsServiceFeatures(any());
+        // features should be the same as before, ImsServiceController will disregard change if it
+        // is the same feature set anyway.
+        verify(carrierController).changeImsServiceFeatures(carrierFeatures);
     }
 
     /**
-     * Bind to device ImsService and change the feature set of the carrier overridden ImsService.
+     * Bind to device ImsServices and change the feature set of the carrier overridden ImsService.
      * Verify that the device and carrier ImsServices are changed.
      */
     @Test
     @SmallTest
     public void testAddCarrierFeature() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE2_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
-        Set<String> deviceFeatures = new HashSet<>();
-        deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
-        deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
+        Set<String> deviceFeatures1 = new HashSet<>();
+        deviceFeatures1.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        Set<String> deviceFeatures2 = new HashSet<>();
+        deviceFeatures2.add(ImsResolver.METADATA_RCS_FEATURE);
+        Set<String> allDeviceFeatures = new HashSet<>(deviceFeatures1);
+        allDeviceFeatures.addAll(deviceFeatures2);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the emergency voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0,
                 ImsFeature.FEATURE_MMTEL));
-        // Use device default package, which will load the ImsService that the device provides
-        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, deviceFeatures, true));
+        // Use device default packages, which will load the ImsServices that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, allDeviceFeatures, true));
+        info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, allDeviceFeatures, true));
         info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
         setupPackageQuery(info);
-        ImsServiceController deviceController = mock(ImsServiceController.class);
+        ImsServiceController deviceController1 = mock(ImsServiceController.class);
+        ImsServiceController deviceController2 = mock(ImsServiceController.class);
         ImsServiceController carrierController = mock(ImsServiceController.class);
-        setImsServiceControllerFactory(deviceController, carrierController);
+        setImsServiceControllerFactory(deviceController1, deviceController2, carrierController,
+                null);
 
         startBindCarrierConfigAlreadySet();
         setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);
@@ -520,27 +1005,34 @@
         verify(carrierController, never()).unbind();
         assertEquals(TEST_CARRIER_DEFAULT_NAME, carrierController.getComponentName());
         // Verify that all features that are not defined in the carrier override are bound in the
-        // device controller (including emergency voice for slot 0)
-        HashSet<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatureSet =
-                convertToHashSet(deviceFeatures, 1);
-        deviceFeatureSet.addAll(convertToHashSet(deviceFeatures, 0));
-        deviceFeatureSet.removeAll(carrierFeatures);
-        verify(deviceController).bind(deviceFeatureSet);
-        verify(deviceController, never()).unbind();
-        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController.getComponentName());
+        // device controllers.
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatureSet1 =
+                convertToHashSet(deviceFeatures1, 1);
+        deviceFeatureSet1.removeAll(carrierFeatures);
+        verify(deviceController1).bind(deviceFeatureSet1);
+        verify(deviceController1, never()).unbind();
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatureSet2 =
+                convertToHashSet(deviceFeatures2, 0);
+        deviceFeatureSet2.addAll(convertToHashSet(deviceFeatures2, 1));
+        deviceFeatureSet2.removeAll(carrierFeatures);
+        verify(deviceController2).bind(deviceFeatureSet2);
+        verify(deviceController2, never()).unbind();
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController1.getComponentName());
+        assertEquals(TEST_DEVICE2_DEFAULT_NAME, deviceController2.getComponentName());
 
         // add RCS to carrier features list
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
 
-        // Tell the package manager that a new device feature is installed
+        // A new carrier feature is installed
         packageChanged(TEST_CARRIER_DEFAULT_NAME.getPackageName());
         setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2);
 
         //Verify new feature is added to the carrier override.
-        // add all features for slot 0
         verify(carrierController).changeImsServiceFeatures(carrierFeatures);
-        deviceFeatureSet.removeAll(carrierFeatures);
-        verify(deviceController).changeImsServiceFeatures(deviceFeatureSet);
+        deviceFeatureSet1.removeAll(carrierFeatures);
+        verify(deviceController1, times(2)).changeImsServiceFeatures(deviceFeatureSet1);
+        deviceFeatureSet2.removeAll(carrierFeatures);
+        verify(deviceController2).changeImsServiceFeatures(deviceFeatureSet2);
     }
 
     /**
@@ -551,13 +1043,14 @@
     @Test
     @SmallTest
     public void testRemoveCarrierFeature() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
@@ -589,7 +1082,7 @@
         carrierFeatures.clear();
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0,
                 ImsFeature.FEATURE_MMTEL));
-        // Tell the package manager that a new device feature is installed
+        //  new carrier feature has been removed
         packageChanged(TEST_CARRIER_DEFAULT_NAME.getPackageName());
         setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2);
 
@@ -611,13 +1104,14 @@
     @Test
     @SmallTest
     public void testInstallCarrierImsService() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         // Use device default package, which will load the ImsService that the device provides
         info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, deviceFeatures, true));
         setupPackageQuery(info);
@@ -653,13 +1147,14 @@
     @Test
     @SmallTest
     public void testUninstallCarrierImsService() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
@@ -697,13 +1192,14 @@
     @Test
     @SmallTest
     public void testCarrierConfigChangedToNone() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
@@ -718,7 +1214,7 @@
         startBindCarrierConfigAlreadySet();
         setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 1);
 
-        setConfigCarrierString(0, null);
+        setConfigCarrierStringMmTelRcs(0, null);
         sendCarrierConfigChanged(0, 0);
 
         // Verify that the carrier controller is unbound
@@ -739,13 +1235,14 @@
     @Test
     @SmallTest
     public void testCarrierConfigChangedToAnotherService() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures1 = new HashSet<>();
         // Carrier service 1
         carrierFeatures1.add(new ImsFeatureConfiguration.FeatureSlotPair(0,
@@ -769,7 +1266,7 @@
         startBindCarrierConfigAlreadySet();
         setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures1, 1);
 
-        setConfigCarrierString(0, TEST_CARRIER_2_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_2_DEFAULT_NAME.getPackageName());
         sendCarrierConfigChanged(0, 0);
         setupDynamicQueryFeatures(TEST_CARRIER_2_DEFAULT_NAME, carrierFeatures2, 1);
 
@@ -796,13 +1293,14 @@
     @Test
     @SmallTest
     public void testBootCompleteNonFbeEnabledCarrierImsService() throws RemoteException {
-        setupResolver(2/*numSlots*/);
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         // Use device default package, which will load the ImsService that the device provides
         info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, deviceFeatures, true));
         setupPackageQuery(info);
@@ -840,13 +1338,14 @@
     @Test
     @SmallTest
     public void testPermanentBindFailureDuringFeatureQuery() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
@@ -881,13 +1380,14 @@
     @Test
     @SmallTest
     public void testPermanentBindFailureDuringBind() throws RemoteException {
-        setupResolver(1/*numSlots*/);
+        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE_DEFAULT_NAME.getPackageName());
         List<ResolveInfo> info = new ArrayList<>();
         Set<String> deviceFeatures = new HashSet<>();
         deviceFeatures.add(ImsResolver.METADATA_MMTEL_FEATURE);
         deviceFeatures.add(ImsResolver.METADATA_RCS_FEATURE);
         // Set the carrier override package for slot 0
-        setConfigCarrierString(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
+        setConfigCarrierStringMmTelRcs(0, TEST_CARRIER_DEFAULT_NAME.getPackageName());
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> carrierFeatures = new HashSet<>();
         // Carrier service doesn't support the voice feature.
         carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(0, ImsFeature.FEATURE_RCS));
@@ -924,14 +1424,166 @@
         verify(deviceController).changeImsServiceFeatures(originalDeviceFeatureSet);
     }
 
-    private void setupResolver(int numSlots) {
+    /**
+     * Bind to device ImsService only, which is configured to be the MMTEL ImsService. Ensure it
+     * does not also try to bind to RCS.
+     */
+    @Test
+    @SmallTest
+    public void testDifferentDevicePackagesMmTelOnly() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(), "");
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features = new HashSet<>();
+        features.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        features.add(ImsResolver.METADATA_RCS_FEATURE);
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, features, true));
+        info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, features, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController deviceController1 = mock(ImsServiceController.class);
+        ImsServiceController deviceController2 = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController1, deviceController2, null, null);
+
+        startBindNoCarrierConfig(1);
+        mLooper.processAllMessages();
+
+        Set<String> featureResult = new HashSet<>();
+        featureResult.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureResultSet =
+                convertToHashSet(featureResult, 0);
+        featureResultSet.addAll(convertToHashSet(featureResult, 1));
+        verify(deviceController1).bind(featureResultSet);
+        verify(deviceController1, never()).unbind();
+        verify(deviceController2, never()).bind(any());
+        verify(deviceController2, never()).unbind();
+        verify(mMockQueryManager, never()).startQuery(any(), any());
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController1.getComponentName());
+    }
+
+    /**
+     * Bind to device ImsService only, which is configured to be the RCS ImsService. Ensure it
+     * does not also try to bind to MMTEL.
+     */
+    @Test
+    @SmallTest
+    public void testDifferentDevicePackagesRcsOnly() throws RemoteException {
+        setupResolver(2 /*numSlots*/, "", TEST_DEVICE_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features = new HashSet<>();
+        features.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        features.add(ImsResolver.METADATA_RCS_FEATURE);
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, features, true));
+        info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, features, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController deviceController1 = mock(ImsServiceController.class);
+        ImsServiceController deviceController2 = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController1, deviceController2, null, null);
+
+        startBindNoCarrierConfig(1);
+        mLooper.processAllMessages();
+
+        Set<String> featureResult = new HashSet<>();
+        featureResult.add(ImsResolver.METADATA_RCS_FEATURE);
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureResultSet =
+                convertToHashSet(featureResult, 0);
+        featureResultSet.addAll(convertToHashSet(featureResult, 1));
+        verify(deviceController1).bind(featureResultSet);
+        verify(deviceController1, never()).unbind();
+        verify(deviceController2, never()).bind(any());
+        verify(deviceController2, never()).unbind();
+        verify(mMockQueryManager, never()).startQuery(any(), any());
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController1.getComponentName());
+    }
+
+    /**
+     * Bind to multiple ImsServices, one for MMTEL and one for RCS. Ensure neither of them bind to
+     * both.
+     */
+    @Test
+    @SmallTest
+    public void testDifferentDevicePackagesMmTelRcs() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE2_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features1 = new HashSet<>();
+        features1.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        Set<String> features2 = new HashSet<>();
+        features2.add(ImsResolver.METADATA_RCS_FEATURE);
+        Set<String> allFeatures = new HashSet<>(features1);
+        allFeatures.addAll(features2);
+        // Use device default package, which will load the ImsService that the device provides
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, allFeatures, true));
+        info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, allFeatures, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController deviceController1 = mock(ImsServiceController.class);
+        ImsServiceController deviceController2 = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController1, deviceController2, null, null);
+
+        startBindNoCarrierConfig(1);
+        mLooper.processAllMessages();
+
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet1 =
+                convertToHashSet(features1, 0);
+        featureSet1.addAll(convertToHashSet(features1, 1));
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> featureSet2 =
+                convertToHashSet(features2, 0);
+        featureSet2.addAll(convertToHashSet(features2, 1));
+        verify(deviceController1).bind(featureSet1);
+        verify(deviceController1, never()).unbind();
+        verify(deviceController2).bind(featureSet2);
+        verify(deviceController2, never()).unbind();
+        verify(mMockQueryManager, never()).startQuery(any(), any());
+        assertEquals(TEST_DEVICE_DEFAULT_NAME, deviceController1.getComponentName());
+        assertEquals(TEST_DEVICE2_DEFAULT_NAME, deviceController2.getComponentName());
+    }
+
+    /**
+     * Set the device configuration to opposite of the supported features in the metadata and ensure
+     * there is no bind.
+     */
+    @Test
+    @SmallTest
+    public void testDifferentDevicePackagesNoSupported() throws RemoteException {
+        setupResolver(2 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
+                TEST_DEVICE2_DEFAULT_NAME.getPackageName());
+        List<ResolveInfo> info = new ArrayList<>();
+        Set<String> features1 = new HashSet<>();
+        features1.add(ImsResolver.METADATA_RCS_FEATURE);
+        Set<String> features2 = new HashSet<>();
+        features2.add(ImsResolver.METADATA_MMTEL_FEATURE);
+        // The configuration is opposite of the device supported features
+        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, features1, true));
+        info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, features2, true));
+        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
+        setupPackageQuery(info);
+        ImsServiceController deviceController1 = mock(ImsServiceController.class);
+        ImsServiceController deviceController2 = mock(ImsServiceController.class);
+        setImsServiceControllerFactory(deviceController1, deviceController2, null, null);
+
+        startBindNoCarrierConfig(1);
+        mLooper.processAllMessages();
+
+        verify(deviceController1, never()).bind(any());
+        verify(deviceController1, never()).unbind();
+        verify(deviceController2, never()).bind(any());
+        verify(deviceController2, never()).unbind();
+        verify(mMockQueryManager, never()).startQuery(any(), any());
+    }
+
+    private void setupResolver(int numSlots, String deviceMmTelPkgName,
+            String deviceRcsPkgName) {
         // all tests call setupResolver before running
         when(mMockContext.getPackageManager()).thenReturn(mMockPM);
+        when(mMockContext.createContextAsUser(any(), eq(0))).thenReturn(mMockContext);
         when(mMockContext.getSystemService(eq(Context.CARRIER_CONFIG_SERVICE))).thenReturn(
                 mMockCarrierConfigManager);
-        when(mMockContext.getPackageManager()).thenReturn(mMockPM);
-        mCarrierConfigs = new PersistableBundle[numSlots];
-        for (int i = 0; i < numSlots; i++) {
+        // Support configs for MSIM always in case we are testing dynamic sim slot config changes.
+        mCarrierConfigs = new PersistableBundle[NUM_MAX_SLOTS];
+        for (int i = 0; i < NUM_MAX_SLOTS; i++) {
             mCarrierConfigs[i] = new PersistableBundle();
             when(mMockCarrierConfigManager.getConfigForSubId(eq(i))).thenReturn(
                     mCarrierConfigs[i]);
@@ -941,24 +1593,20 @@
                     TelephonyManager.SIM_STATE_READY);
         }
 
-        mTestImsResolver = new ImsResolver(mMockContext, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
-                numSlots, true);
+        mTestImsResolver = new ImsResolver(mMockContext, deviceMmTelPkgName, deviceRcsPkgName,
+                numSlots);
         try {
             mLooper = new TestableLooper(mTestImsResolver.getHandler().getLooper());
         } catch (Exception e) {
             fail("Unable to create looper from handler.");
         }
 
-        ArgumentCaptor<BroadcastReceiver> packageBroadcastCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
         ArgumentCaptor<BroadcastReceiver> receiversCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mMockContext).registerReceiverAsUser(packageBroadcastCaptor.capture(), any(),
-                any(), any(), any());
-        mTestPackageBroadcastReceiver = packageBroadcastCaptor.getValue();
-        verify(mMockContext, times(2)).registerReceiver(receiversCaptor.capture(), any());
-        mTestCarrierConfigReceiver = receiversCaptor.getAllValues().get(0);
-        mTestBootCompleteReceiver = receiversCaptor.getAllValues().get(1);
+        verify(mMockContext, times(3)).registerReceiver(receiversCaptor.capture(), any());
+        mTestPackageBroadcastReceiver = receiversCaptor.getAllValues().get(0);
+        mTestCarrierConfigReceiver = receiversCaptor.getAllValues().get(1);
+        mTestBootCompleteReceiver = receiversCaptor.getAllValues().get(2);
         mTestImsResolver.setSubscriptionManagerProxy(mTestSubscriptionManagerProxy);
         mTestImsResolver.setTelephonyManagerProxy(mTestTelephonyManagerProxy);
         when(mMockQueryManagerFactory.create(any(Context.class),
@@ -1127,6 +1775,41 @@
                 });
     }
 
+    private void setImsServiceControllerFactory(ImsServiceController deviceController1,
+            ImsServiceController deviceController2, ImsServiceController carrierController1,
+            ImsServiceController carrierController2) {
+        mTestImsResolver.setImsServiceControllerFactory(
+                new ImsResolver.ImsServiceControllerFactory() {
+                    @Override
+                    public String getServiceInterface() {
+                        return ImsService.SERVICE_INTERFACE;
+                    }
+
+                    @Override
+                    public ImsServiceController create(Context context, ComponentName componentName,
+                            ImsServiceController.ImsServiceControllerCallbacks callbacks) {
+                        if (TEST_DEVICE_DEFAULT_NAME.getPackageName().equals(
+                                componentName.getPackageName())) {
+                            when(deviceController1.getComponentName()).thenReturn(componentName);
+                            return deviceController1;
+                        } else if (TEST_DEVICE2_DEFAULT_NAME.getPackageName().equals(
+                                componentName.getPackageName())) {
+                            when(deviceController2.getComponentName()).thenReturn(componentName);
+                            return deviceController2;
+                        } else if (TEST_CARRIER_DEFAULT_NAME.getPackageName().equals(
+                                componentName.getPackageName())) {
+                            when(carrierController1.getComponentName()).thenReturn(componentName);
+                            return carrierController1;
+                        } else if (TEST_CARRIER_2_DEFAULT_NAME.getPackageName().equals(
+                                componentName.getPackageName())) {
+                            when(carrierController2.getComponentName()).thenReturn(componentName);
+                            return carrierController2;
+                        }
+                        return null;
+                    }
+                });
+    }
+
 
     private void sendCarrierConfigChanged(int subId, int slotId) {
         Intent carrierConfigIntent = new Intent();
@@ -1136,11 +1819,21 @@
         mLooper.processAllMessages();
     }
 
-    private void setConfigCarrierString(int subId, String packageName) {
+    private void setConfigCarrierStringMmTelRcs(int subId, String packageName) {
         mCarrierConfigs[subId].putString(
                 CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, packageName);
     }
 
+    private void setConfigCarrierStringMmTel(int subId, String packageName) {
+        mCarrierConfigs[subId].putString(
+                CarrierConfigManager.KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING, packageName);
+    }
+
+    private void setConfigCarrierStringRcs(int subId, String packageName) {
+        mCarrierConfigs[subId].putString(
+                CarrierConfigManager.KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING, packageName);
+    }
+
     private HashSet<ImsFeatureConfiguration.FeatureSlotPair> convertToHashSet(
             Set<String> features, int slotId) {
         return features.stream()
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
index 85a83ce..ff17216 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
@@ -38,6 +38,7 @@
 import android.os.RemoteException;
 import android.telephony.ims.ImsService;
 import android.telephony.ims.aidl.IImsServiceController;
+import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -60,6 +61,9 @@
 @RunWith(AndroidJUnit4.class)
 public class ImsServiceControllerTest extends ImsTestBase {
 
+    private static final int SLOT_0 = 0;
+    private static final int SLOT_1 = 1;
+
     private static final ImsServiceController.RebindRetry REBIND_RETRY =
             new ImsServiceController.RebindRetry() {
         @Override
@@ -110,10 +114,10 @@
     @Test
     public void testBindService() {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ArgumentCaptor<Intent> intentCaptor =
                 ArgumentCaptor.forClass(Intent.class);
 
@@ -134,8 +138,8 @@
     @Test
     public void testBindFailureWhenBound() {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
         bindAndConnectService(testFeatures);
 
         // already bound, should return false
@@ -152,21 +156,21 @@
     @Test
     public void testBindServiceAndConnected() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
 
         bindAndConnectService(testFeatures);
 
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(1), any());
-        verify(mMockServiceControllerBinder).createRcsFeature(eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockServiceControllerBinder).createRcsFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(2),
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(2));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS));
     }
 
     /**
@@ -177,24 +181,56 @@
     @Test
     public void testBindEmergencyMmTel() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, Emergency MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 0));
-        // Slot 1, MmTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
 
         bindAndConnectService(testFeatures);
 
-        // We do not want this callback to happen for emergency MMTEL
-        verify(mMockServiceControllerBinder, never()).createMmTelFeature(eq(0), any());
-        verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(1), eq(0),
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
-                eq(mTestImsServiceController));
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_EMERGENCY_MMTEL), eq(mTestImsServiceController));
         // Make sure this callback happens, which will notify the framework of emergency calling
         // availability.
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(0));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+    }
+
+    /**
+     * Tests to make sure that if EMERGENCY_MMTEL is specified, but not MMTEL, we do not bind to
+     * MMTEL.
+     */
+    @SmallTest
+    @Test
+    public void testBindEmergencyMmTelButNotMmTel() throws RemoteException {
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        // did not add FEATURE_MMTEL
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
+
+        bindAndConnectService(testFeatures);
+
+        // Verify no MMTEL or EMERGENCY_MMTEL features are created
+        verify(mMockServiceControllerBinder, never()).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_MMTEL), eq(mTestImsServiceController));
+        verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_EMERGENCY_MMTEL), eq(mTestImsServiceController));
+        verify(mMockProxyCallbacks, never()).imsFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        verify(mMockProxyCallbacks, never()).imsFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_MMTEL));
+        // verify RCS feature is created
+        verify(mMockServiceControllerBinder).createRcsFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS),
+                eq(mTestImsServiceController));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS));
     }
 
     /**
@@ -205,10 +241,10 @@
     @Test
     public void testCallbacksHappenWhenAddedAfterBind() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, Emergency MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 0));
-        // Slot 1, MmTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
         mTestImsServiceController.removeImsServiceFeatureCallbacks();
 
         bindAndConnectService(testFeatures);
@@ -216,8 +252,9 @@
         mTestImsServiceController.addImsServiceFeatureCallback(mMockProxyCallbacks);
 
         // Make sure this callback happens for Emergency MMTEL and MMTEL
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(0));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_EMERGENCY_MMTEL));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
     }
 
     /**
@@ -228,20 +265,20 @@
     @Test
     public void testBindServiceAndConnectedDisconnected() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ServiceConnection conn = bindAndConnectService(testFeatures);
 
         conn.onServiceDisconnected(mTestComponentName);
 
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2),
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS));
     }
 
     /**
@@ -252,23 +289,25 @@
     @Test
     public void testBindServiceBindUnbind() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ServiceConnection conn = bindAndConnectService(testFeatures);
 
         mTestImsServiceController.unbind();
 
         verify(mMockContext).unbindService(eq(conn));
-        verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(1), any());
-        verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(2), any());
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
+        verify(mMockServiceControllerBinder).removeImsFeature(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_MMTEL), any());
+        verify(mMockServiceControllerBinder).removeImsFeature(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_RCS), any());
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2),
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS));
     }
 
     /**
@@ -278,20 +317,20 @@
     @Test
     public void testBindServiceAndBinderDied() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ServiceConnection conn = bindAndConnectService(testFeatures);
 
         conn.onBindingDied(null /*null*/);
 
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2),
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS));
     }
 
     /**
@@ -301,10 +340,10 @@
     @Test
     public void testBindServiceAndReturnedNull() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
 
         bindAndNullServiceError(testFeatures);
 
@@ -321,24 +360,85 @@
     @Test
     public void testBindServiceAndAddFeature() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
         bindAndConnectService(testFeatures);
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
         // Create a new list with an additional item
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithAddition = new HashSet<>(
                 testFeatures);
-        testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
+        testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_1,
+                ImsFeature.FEATURE_MMTEL));
 
         mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithAddition);
 
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(2), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1),
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_1), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL));
+    }
+
+    /**
+     * Ensures that the when EMERGENCY_MMTEL_FEATURE is defined but not MMTEL_FEATURE when the
+     * features are changed, we do not bind to MMTEL.
+     */
+    @SmallTest
+    @Test
+    public void testBindServiceAndAddEmergencyButNotMmtel() throws RemoteException {
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
+        bindAndConnectService(testFeatures);
+        verify(mMockServiceControllerBinder).createRcsFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS),
+                eq(mTestImsServiceController));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS));
+        // Add FEATURE_EMERGENCY_MMTEL and ensure it doesn't cause MMTEL bind
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithAddition = new HashSet<>(
+                testFeatures);
+        testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_1,
+                ImsFeature.FEATURE_EMERGENCY_MMTEL));
+
+        mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithAddition);
+
+        verify(mMockServiceControllerBinder, never()).createMmTelFeature(eq(SLOT_1), any());
+        verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(SLOT_1),
+                eq(ImsFeature.FEATURE_MMTEL),
+                eq(mTestImsServiceController));
+        verify(mMockProxyCallbacks, never()).imsFeatureCreated(eq(SLOT_1),
+                eq(ImsFeature.FEATURE_MMTEL));
+    }
+
+    /**
+     * Ensures ImsServiceController disregards changes to features that result in the same feature
+     * set.
+     */
+    @SmallTest
+    @Test
+    public void testBindServiceCallChangeWithNoNewFeatures() throws RemoteException {
+        HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        bindAndConnectService(testFeatures);
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
+                eq(mTestImsServiceController));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+
+        // Call change with the same features and make sure it is disregarded
+        mTestImsServiceController.changeImsServiceFeatures(testFeatures);
+
+        verify(mMockServiceControllerBinder, times(1)).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockServiceControllerBinder, never()).removeImsFeature(anyInt(), anyInt(), any());
+        verify(mMockCallbacks, times(1)).imsServiceFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_MMTEL), eq(mTestImsServiceController));
+        verify(mMockCallbacks, never()).imsServiceFeatureRemoved(anyInt(), anyInt(), any());
+        verify(mMockProxyCallbacks, times(1)).imsFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockProxyCallbacks, never()).imsFeatureRemoved(anyInt(), anyInt());
     }
 
     /**
@@ -348,30 +448,32 @@
     @Test
     public void testBindServiceAndRemoveFeature() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 2, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_1,
+                ImsFeature.FEATURE_MMTEL));
         bindAndConnectService(testFeatures);
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(2), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1),
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_1), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL));
         // Create a new list with one less item
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithSubtraction =
                 new HashSet<>(testFeatures);
-        testFeaturesWithSubtraction.remove(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
+        testFeaturesWithSubtraction.remove(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_1,
+                ImsFeature.FEATURE_MMTEL));
 
         mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithSubtraction);
 
-        verify(mMockServiceControllerBinder).removeImsFeature(eq(2), eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(2), eq(1),
+        verify(mMockServiceControllerBinder).removeImsFeature(eq(SLOT_1),
+                eq(ImsFeature.FEATURE_MMTEL), any());
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(2), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL));
     }
 
     /**
@@ -381,31 +483,33 @@
     @Test
     public void testBindServiceAndRemoveAllFeatures() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // slot 2, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_1,
+                ImsFeature.FEATURE_MMTEL));
         bindAndConnectService(testFeatures);
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1),
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1));
-        verify(mMockServiceControllerBinder).createMmTelFeature(eq(2), any());
-        verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1),
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockServiceControllerBinder).createMmTelFeature(eq(SLOT_1), any());
+        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureCreated(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL));
 
         // Create a new empty list
         mTestImsServiceController.changeImsServiceFeatures(new HashSet<>());
 
-        verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1),
+        verify(mMockServiceControllerBinder).removeImsFeature(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_MMTEL), any());
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1));
-        verify(mMockServiceControllerBinder).removeImsFeature(eq(2), eq(1), any());
-        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(2), eq(1),
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL));
+        verify(mMockServiceControllerBinder).removeImsFeature(eq(SLOT_1),
+                eq(ImsFeature.FEATURE_MMTEL), any());
+        verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL),
                 eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(2), eq(1));
+        verify(mMockProxyCallbacks).imsFeatureRemoved(eq(SLOT_1), eq(ImsFeature.FEATURE_MMTEL));
     }
 
     /**
@@ -415,22 +519,24 @@
     @Test
     public void testBindUnbindServiceAndAddFeature() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
         bindAndConnectService(testFeatures);
         mTestImsServiceController.unbind();
         // Create a new list with an additional item
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithAddition = new HashSet<>(
                 testFeatures);
         // Try to create an RCS feature
-        testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
 
         mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithAddition);
 
-        verify(mMockServiceControllerBinder, never()).createRcsFeature(eq(1), any());
-        verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(1), eq(2),
-                eq(mTestImsServiceController));
-        verify(mMockProxyCallbacks, never()).imsFeatureCreated(eq(1), eq(2));
+        verify(mMockServiceControllerBinder, never()).createRcsFeature(eq(SLOT_0), any());
+        verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_RCS), eq(mTestImsServiceController));
+        verify(mMockProxyCallbacks, never()).imsFeatureCreated(eq(SLOT_0),
+                eq(ImsFeature.FEATURE_RCS));
     }
 
     /**
@@ -441,10 +547,10 @@
     @Test
     public void testAutoBindAfterBinderDied() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ServiceConnection conn = bindAndConnectService(testFeatures);
 
         conn.onBindingDied(null /*null*/);
@@ -462,10 +568,10 @@
     @Test
     public void testNoAutoBindBeforeTimeout() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ServiceConnection conn = bindAndConnectService(testFeatures);
 
         conn.onBindingDied(null /*null*/);
@@ -481,10 +587,10 @@
     @Test
     public void testUnbindCauseAutoBindCancelAfterBinderDied() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ServiceConnection conn = bindAndConnectService(testFeatures);
 
         conn.onBindingDied(null /*null*/);
@@ -505,10 +611,10 @@
     @Test
     public void testBindCauseAutoBindCancelAfterBinderDied() throws RemoteException {
         HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
-        // Slot 1, MMTel
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1));
-        // Slot 1, RCS
-        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_MMTEL));
+        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
+                ImsFeature.FEATURE_RCS));
         ServiceConnection conn = bindAndConnectService(testFeatures);
         conn.onBindingDied(null /*null*/);
         mTestImsServiceController.bind(testFeatures);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/MmTelFeatureConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/MmTelFeatureConnectionTest.java
index b715d48..87b8a56 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/MmTelFeatureConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/MmTelFeatureConnectionTest.java
@@ -34,7 +34,7 @@
 import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.ims.MmTelFeatureConnection;
+import com.android.ims.ImsCallbackAdapterManager;
 import com.android.internal.telephony.TelephonyTest;
 
 import org.junit.After;
@@ -55,7 +55,7 @@
     }
 
     private class CallbackManagerTest extends
-            MmTelFeatureConnection.CallbackAdapterManager<TestCallback> {
+            ImsCallbackAdapterManager<TestCallback> {
 
         List<TestCallback> mCallbacks = new ArrayList<>();
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsFeatureConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/RcsFeatureConnectionTest.java
deleted file mode 100644
index 1d31509..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsFeatureConnectionTest.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import junit.framework.AssertionFailedError;
-
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.telephony.SubscriptionManager;
-import android.telephony.ims.RcsContactUceCapability;
-import android.telephony.ims.aidl.IImsCapabilityCallback;
-import android.telephony.ims.aidl.IImsRcsFeature;
-import android.telephony.ims.aidl.IRcsFeatureListener;
-import android.telephony.ims.feature.CapabilityChangeRequest;
-import android.telephony.ims.feature.ImsFeature;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.ims.RcsFeatureConnection;
-import com.android.ims.internal.IImsServiceFeatureCallback;
-import com.android.internal.telephony.TelephonyTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-public class RcsFeatureConnectionTest extends TelephonyTest {
-
-    private Executor mSimpleExecutor = new Executor() {
-        @Override
-        public void execute(Runnable r) {
-            r.run();
-        }
-    };
-
-    private IImsRcsFeature mTestImsRcsFeatureBinder = new IImsRcsFeature.Stub() {
-        @Override
-        public void setListener(IRcsFeatureListener listener) {
-        }
-
-        @Override
-        public int queryCapabilityStatus() {
-            return 1;
-        }
-
-        @Override
-        public int getFeatureState() {
-            return ImsFeature.STATE_READY;
-        }
-
-        @Override
-        public void addCapabilityCallback(IImsCapabilityCallback c) {
-        }
-
-        @Override
-        public void removeCapabilityCallback(IImsCapabilityCallback c) {
-        }
-
-        @Override
-        public void changeCapabilitiesConfiguration(CapabilityChangeRequest r,
-                IImsCapabilityCallback c) {
-        }
-
-        @Override
-        public void queryCapabilityConfiguration(int capability, int radioTech,
-                IImsCapabilityCallback c) {
-        }
-
-        @Override
-        public void requestCapabilities(List<Uri> uris, int operationToken) {
-        }
-
-        @Override
-        public void updateCapabilities(RcsContactUceCapability capabilities,
-                int operationToken) {
-        }
-
-        @Override
-        public void sendCapabilityRequest(Uri contactUri,
-                RcsContactUceCapability capabilities, int operationToken) {
-        }
-
-        @Override
-        public void respondToCapabilityRequest(String contactUri,
-                RcsContactUceCapability ownCapabilities, int operationToken) {
-        }
-
-        @Override
-        public void respondToCapabilityRequestWithError(Uri contactUri, int code,
-                String reason, int operationToken) {
-        }
-    };
-
-    private int mPhoneId;
-    private SubscriptionManager mSubscriptionManager;
-    private RcsFeatureConnection mRcsFeatureConnection;
-
-    @Mock
-    RcsFeatureConnection.RcsFeatureManagerProxy mRcsFeatureManagerProxy;
-    @Mock
-    RcsFeatureConnection.IRcsFeatureUpdate mCallback;
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp("RcsFeatureConnectionTest");
-        mPhoneId = mPhone.getPhoneId();
-
-        mSubscriptionManager = (SubscriptionManager) mContext.getSystemService(
-                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-
-        doReturn(null).when(mContext).getMainLooper();
-        doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
-
-        mRcsFeatureConnection = RcsFeatureConnection.create(mContext, mPhoneId, null);
-        mRcsFeatureConnection.mExecutor = mSimpleExecutor;
-        mRcsFeatureConnection.setBinder(mTestImsRcsFeatureBinder.asBinder());
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    /**
-     * Test that RcsFeatureConnection is ready when RCS UCE is supported by device and carrier.
-     */
-    @Test
-    @SmallTest
-    public void testServiceIsReady() {
-        // RCS UCE is supported by carrier
-        setRcsUceIsSupportedByCarrier(true);
-        try {
-            mRcsFeatureConnection.checkServiceIsReady();
-        } catch (RemoteException e) {
-            throw new AssertionFailedError("Exception in checkServiceIsReady: " + e);
-        }
-    }
-
-    /**
-     * Test that RcsFeatureConnection is not ready when RCS UCE is not supported carrier.
-     */
-    @Test
-    @SmallTest
-    public void testServiceIsNotSupportedByCarrier() {
-        // RCS UCE feature is NOT supported by carrier
-        setRcsUceIsSupportedByCarrier(false);
-        try {
-            mRcsFeatureConnection.checkServiceIsReady();
-            throw new AssertionFailedError("Exception in testServiceIsNotSupportedByCarrier");
-        } catch (RemoteException e) {
-            //expected result
-        }
-    }
-
-    private void setRcsUceIsSupportedByCarrier(boolean isSupported) {
-        when(mRcsFeatureManagerProxy.isRcsUceSupportedByCarrier(mContext, 0))
-                .thenReturn(isSupported);
-        RcsFeatureConnection.setRcsFeatureManagerProxy(mRcsFeatureManagerProxy);
-    }
-
-    /**
-     * Test that service is not ready after IMS feature is removed.
-     */
-    @Test
-    @SmallTest
-    public void testImsFeatureRemoved() {
-        setRcsUceIsSupportedByCarrier(true);
-        IImsServiceFeatureCallback imsServiceCallback = mRcsFeatureConnection.getListener();
-        try {
-            imsServiceCallback.imsFeatureRemoved(0, ImsFeature.FEATURE_RCS);
-            mRcsFeatureConnection.checkServiceIsReady();
-            throw new AssertionFailedError("testImsFeatureRemoved");
-        } catch (RemoteException e) {
-            //expected result
-        }
-    }
-
-    /**
-     * Test that service is not ready after the status of IMS feature is unavailable.
-     */
-    @Test
-    @SmallTest
-    public void testImsStatusIsUnavailable() {
-        setRcsUceIsSupportedByCarrier(true);
-        IImsServiceFeatureCallback imsServiceCallback = mRcsFeatureConnection.getListener();
-        try {
-            imsServiceCallback.imsStatusChanged(0, ImsFeature.FEATURE_RCS,
-                    ImsFeature.STATE_UNAVAILABLE);
-            mRcsFeatureConnection.checkServiceIsReady();
-            throw new AssertionFailedError("testImsStatusIsUnavailable");
-        } catch (RemoteException e) {
-            //expected result
-        }
-    }
-
-    /**
-     * Test that service is ready when the status is unavailable on different slot.
-     */
-    @Test
-    @SmallTest
-    public void testImsStatusUnavailableOnDifferentSlot() {
-        setRcsUceIsSupportedByCarrier(true);
-        IImsServiceFeatureCallback imsServiceCallback = mRcsFeatureConnection.getListener();
-        try {
-            imsServiceCallback.imsFeatureRemoved(1, ImsFeature.FEATURE_RCS);
-            mRcsFeatureConnection.checkServiceIsReady();
-        } catch (RemoteException e) {
-            throw new AssertionFailedError("testImsStatusUnavailableOnDifferentSlot: " + e);
-        }
-    }
-
-    /**
-     * Test that service is ready when the status is unavailable on different ImsFeature.
-     */
-    @Test
-    @SmallTest
-    public void testImsStatusUnavailableOnDifferentFeature() {
-        setRcsUceIsSupportedByCarrier(true);
-        IImsServiceFeatureCallback imsServiceCallback = mRcsFeatureConnection.getListener();
-        try {
-            imsServiceCallback.imsFeatureRemoved(1, ImsFeature.FEATURE_MMTEL);
-            mRcsFeatureConnection.checkServiceIsReady();
-        } catch (RemoteException e) {
-            throw new AssertionFailedError("testImsStatusUnavailableOnDifferentFeature: " + e);
-        }
-    }
-
-    @Test
-    @SmallTest
-    public void testRetrieveFeatureState() {
-        assertNotNull(mRcsFeatureConnection.retrieveFeatureState());
-    }
-
-    @Test
-    @SmallTest
-    public void testFeatureStatusCallback() {
-        mRcsFeatureConnection.setStatusCallback(mCallback);
-
-        mRcsFeatureConnection.handleImsFeatureCreatedCallback(mPhoneId, ImsFeature.FEATURE_RCS);
-        verify(mCallback).notifyFeatureCreated();
-
-        mRcsFeatureConnection.handleImsFeatureRemovedCallback(mPhoneId, ImsFeature.FEATURE_RCS);
-        verify(mCallback).notifyUnavailable();
-
-        mRcsFeatureConnection.handleImsStatusChangedCallback(mPhoneId, ImsFeature.FEATURE_RCS,
-                ImsFeature.STATE_READY);
-        verify(mCallback).notifyStateChanged();
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsFeatureManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/RcsFeatureManagerTest.java
deleted file mode 100644
index b4ea898..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsFeatureManagerTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2019 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.ims;
-
-import junit.framework.AssertionFailedError;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyObject;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.pm.PackageManager;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.telephony.CarrierConfigManager;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.ims.ImsException;
-import com.android.ims.RcsFeatureConnection;
-import com.android.ims.RcsFeatureManager;
-import com.android.internal.telephony.TelephonyTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-
-public class RcsFeatureManagerTest extends TelephonyTest {
-
-    private int mPhoneId;
-    private PersistableBundle mCarrierConfigBundle;
-    private RcsFeatureManager mRcsFeatureManager;
-    @Mock
-    RcsFeatureConnection mRcsFeatureConnection;
-    @Mock
-    RcsFeatureConnection.IRcsFeatureUpdate mStatusCallback;
-    @Mock
-    RcsFeatureManager.SubscriptionManagerProxy mSubscriptionManagerProxy;
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp("RcsFeatureManagerTest");
-        mPhoneId = mPhone.getPhoneId();
-        mCarrierConfigBundle = mContextFixture.getCarrierConfigBundle();
-
-        doReturn(null).when(mContext).getMainLooper();
-        doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
-
-        when(mSubscriptionManagerProxy.getSubId(0)).thenReturn(1);
-        RcsFeatureManager.setSubscriptionManager(mSubscriptionManagerProxy);
-
-        mRcsFeatureManager = new RcsFeatureManager(mContext, mPhoneId);
-        mRcsFeatureManager.mRcsFeatureConnection = mRcsFeatureConnection;
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    /**
-     * Test RCS UCE feature is supported by carrier
-     */
-    @Test
-    @SmallTest
-    public void testRcsUceFeatureIsSupportedByCarrier() {
-        int phoneId = mPhone.getPhoneId();
-
-        // RCS UCE is supported by carrier
-        setIsSupportedByCarrier(true, true);
-        assertTrue(RcsFeatureManager.isRcsUceSupportedByCarrier(mContext, phoneId));
-
-        // RCS UCE is not supported by carrier
-        setIsSupportedByCarrier(false, false);
-        assertFalse(RcsFeatureManager.isRcsUceSupportedByCarrier(mContext, phoneId));
-    }
-
-    private void setIsSupportedByCarrier(boolean isOptionsSupported, boolean isPresenceSupported) {
-        mCarrierConfigBundle.putBoolean(
-                CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, isOptionsSupported);
-        mCarrierConfigBundle.putBoolean(
-                CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, isPresenceSupported);
-    }
-
-    /**
-     * Test ImsFeature status can be add/remove successfully
-     */
-    @Test
-    @SmallTest
-    public void testAddRemoveStatusChangedCallback() {
-        // Verify the size of callbacks after add a status callback into RcsFeatureManager
-        when(mRcsFeatureConnection.isBinderAlive()).thenReturn(true);
-        try {
-            mRcsFeatureManager.addNotifyStatusChangedCallbackIfAvailable(mStatusCallback);
-        } catch (ImsException e) {
-            throw new AssertionFailedError("testAddStatusChangedCallback: " + e);
-        }
-        int currentSize = mRcsFeatureManager.mStatusCallbacks.size();
-        assertEquals(1, currentSize);
-
-        // Verify callback size is zero after remove a status callback into RcsFeatureManager
-        mRcsFeatureManager.removeNotifyStatusChangedCallback(mStatusCallback);
-        currentSize = mRcsFeatureManager.mStatusCallbacks.size();
-        assertEquals(0, currentSize);
-    }
-
-    @Test
-    @SmallTest
-    public void testChangeEnabledCapabilities() {
-        // RCS UCE supported by carrier
-        setIsSupportedByCarrier(true, true);
-        // change enable UCE capability
-        mRcsFeatureManager.changeEnabledCapabilitiesAfterRcsFeatureCreated();
-        try {
-            // verify the request "changeEnabledCapabilities" will be called
-            verify(mRcsFeatureConnection).changeEnabledCapabilities(anyObject(), anyObject());
-        } catch (RemoteException e) {
-            throw new AssertionFailedError("testChangeEnabledCapabilities: " + e);
-        }
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java
deleted file mode 100644
index 47c0564..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2019 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.ims;
-
-import static android.provider.Telephony.RcsColumns.Rcs1To1ThreadColumns.FALLBACK_THREAD_ID_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_ICON_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.GROUP_NAME_COLUMN;
-import static android.provider.Telephony.RcsColumns.RcsGroupThreadColumns.OWNER_PARTICIPANT_COLUMN;
-import static android.telephony.ims.RcsThreadQueryParams.THREAD_TYPE_GROUP;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-
-import android.content.ContentValues;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.provider.Telephony;
-import android.provider.Telephony.RcsColumns.RcsParticipantColumns;
-import android.telephony.ims.RcsParticipant;
-import android.telephony.ims.RcsThreadQueryParams;
-import android.test.mock.MockContentResolver;
-
-import com.android.internal.telephony.TelephonyTest;
-import com.android.internal.telephony.ims.FakeProviderWithAsserts.ExpectedInsert;
-import com.android.internal.telephony.ims.FakeProviderWithAsserts.ExpectedQuery;
-import com.android.internal.telephony.ims.FakeProviderWithAsserts.ExpectedUpdate;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class RcsMessageStoreControllerTest extends TelephonyTest {
-
-    private RcsMessageController mRcsMessageController;
-    private MockContentResolver mContentResolver;
-    private FakeProviderWithAsserts mFakeRcsProvider;
-
-    @Mock
-    RcsParticipant mMockParticipant;
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp("RcsMessageStoreControllerTest");
-        MockitoAnnotations.initMocks(this);
-
-        mFakeRcsProvider = new FakeProviderWithAsserts();
-        mContentResolver = (MockContentResolver) mContext.getContentResolver();
-        mContentResolver.addProvider("rcs", mFakeRcsProvider);
-
-        mRcsMessageController = new RcsMessageController(mContext);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    @Test
-    public void testGetRcsThreads() {
-        doReturn(123).when(mMockParticipant).getId();
-        RcsThreadQueryParams queryParameters =
-                new RcsThreadQueryParams.Builder().setParticipant(mMockParticipant)
-                        .setThreadType(THREAD_TYPE_GROUP).setResultLimit(30).build();
-
-        // TODO - limit the query as per queryParameters. This will change how the query is executed
-        mFakeRcsProvider.addExpectedOperation(new ExpectedQuery(
-                Uri.parse("content://rcs/thread"), null, null, null, null, null));
-
-        try {
-            mRcsMessageController.getRcsThreads(queryParameters, getPackageName());
-        } catch (RuntimeException e) {
-            // eat the exception as there is no provider - we care about the expected update assert
-        }
-    }
-
-    @Test
-    public void testCreateRcsParticipant() {
-        String canonicalAddress = "+5551234567";
-
-        // verify the first query to canonical addresses
-        MatrixCursor canonicalAddressQueryCursor = new MatrixCursor(
-                new String[]{Telephony.CanonicalAddressesColumns._ID});
-        canonicalAddressQueryCursor.addRow(new Object[]{456});
-
-        Uri expectedCanonicalAddressUri = Uri.parse("content://rcs/canonical-address")
-                .buildUpon()
-                .appendQueryParameter("address", canonicalAddress)
-                .build();
-
-        mFakeRcsProvider.addExpectedOperation(new ExpectedQuery(
-                expectedCanonicalAddressUri, null, null, null, null, canonicalAddressQueryCursor));
-
-
-        // verify the final insert on rcs participants
-        ContentValues expectedRcsValues = new ContentValues(1);
-        expectedRcsValues.put(RcsParticipantColumns.CANONICAL_ADDRESS_ID_COLUMN, 456);
-        expectedRcsValues.put(RcsParticipantColumns.RCS_ALIAS_COLUMN, "alias");
-        mFakeRcsProvider.addExpectedOperation(new ExpectedInsert(
-                Uri.parse("content://rcs/participant"), expectedRcsValues,
-                Uri.parse("content://rcs/participant/1001")));
-
-        int participantId =
-                mRcsMessageController.createRcsParticipant(canonicalAddress, "alias",
-                        getPackageName());
-
-        assertThat(participantId).isEqualTo(1001);
-    }
-
-    @Test
-    public void testUpdateRcsParticipantAlias() {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put("rcs_alias", "New Alias");
-        mFakeRcsProvider.addExpectedOperation(new ExpectedUpdate(
-                Uri.parse("content://rcs/participant/551"), null, null, contentValues, 0));
-
-        try {
-            mRcsMessageController.setRcsParticipantAlias(551, "New Alias", getPackageName());
-        } catch (RuntimeException e) {
-            // eat the exception as there is no provider - we care about the expected update assert
-        }
-    }
-
-    @Test
-    public void testSet1To1ThreadFallbackThreadId() {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(FALLBACK_THREAD_ID_COLUMN, 456L);
-        mFakeRcsProvider.addExpectedOperation(new ExpectedUpdate(
-                Uri.parse("content://rcs/p2p_thread/123"), null, null, contentValues, 0));
-        try {
-            mRcsMessageController.set1To1ThreadFallbackThreadId(123, 456L, getPackageName());
-        } catch (RuntimeException e) {
-            // eat the exception as there is no provider - we care about the expected update assert
-        }
-    }
-
-    @Test
-    public void testSetGroupThreadName() {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(GROUP_NAME_COLUMN, "new name");
-        mFakeRcsProvider.addExpectedOperation(new ExpectedUpdate(
-                Uri.parse("content://rcs/group_thread/345"), null, null, contentValues, 0));
-
-        try {
-            mRcsMessageController.setGroupThreadName(345, "new name", getPackageName());
-        } catch (RuntimeException e) {
-            // eat the exception as there is no provider - we care about the expected update assert
-        }
-    }
-
-    @Test
-    public void testSetGroupThreadIcon() {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(GROUP_ICON_COLUMN, "newIcon");
-        mFakeRcsProvider.addExpectedOperation(new ExpectedUpdate(
-                Uri.parse("content://rcs/group_thread/345"), null, null, contentValues, 0));
-
-        try {
-            mRcsMessageController.setGroupThreadIcon(345, Uri.parse("newIcon"),
-                    getPackageName());
-        } catch (RuntimeException e) {
-            // eat the exception as there is no provider - we care about the expected update assert
-        }
-    }
-
-    @Test
-    public void testSetGroupThreadOwner() {
-        ContentValues contentValues = new ContentValues(1);
-        contentValues.put(OWNER_PARTICIPANT_COLUMN, 9);
-        mFakeRcsProvider.addExpectedOperation(new ExpectedUpdate(
-                Uri.parse("content://rcs/group_thread/454"), null, null, contentValues, 0));
-
-        try {
-            mRcsMessageController.setGroupThreadOwner(454, 9, getPackageName());
-        } catch (RuntimeException e) {
-            // eat the exception as there is no provider - we care about the expected update assert
-        }
-    }
-
-    private String getPackageName() {
-        return mContext.getOpPackageName();
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallTest.java
index d64c69d..f84713e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallTest.java
@@ -16,25 +16,24 @@
 
 package com.android.internal.telephony.imsphone;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.os.Bundle;
 import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsCallProfile;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.ims.ImsCall;
-import android.telephony.ims.ImsCallProfile;
-
 import com.android.internal.telephony.TelephonyTest;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doReturn;
-
 public class ImsCallTest extends TelephonyTest {
 
     private Bundle mBundle;
@@ -54,14 +53,27 @@
 
     @Test
     @SmallTest
-    public void testSetWifi() {
+    public void testSetWifiDeprecated() {
         ImsCall mTestImsCall = new ImsCall(mContext, mTestCallProfile);
         assertFalse(mTestImsCall.isWifiCall());
-        assertNotEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
+        // use deprecated API
         mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
                 ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + "");
         assertTrue(mTestImsCall.isWifiCall());
-        assertNotEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
+    }
+
+    @Test
+    @SmallTest
+    public void testSetWifi() {
+        ImsCall mTestImsCall = new ImsCall(mContext, mTestCallProfile);
+        assertFalse(mTestImsCall.isWifiCall());
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
+        mBundle.putInt(ImsCallProfile.EXTRA_CALL_NETWORK_TYPE,
+                TelephonyManager.NETWORK_TYPE_IWLAN);
+        assertTrue(mTestImsCall.isWifiCall());
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
     }
 
     @Test
@@ -69,11 +81,23 @@
     public void testSetWifiAlt() {
         ImsCall mTestImsCall = new ImsCall(mContext, mTestCallProfile);
         assertFalse(mTestImsCall.isWifiCall());
-        assertNotEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
         mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT,
                 ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + "");
         assertTrue(mTestImsCall.isWifiCall());
-        assertNotEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
+    }
+
+    @Test
+    @SmallTest
+    public void testSetLteNoWifiDeprecated() {
+        ImsCall mTestImsCall = new ImsCall(mContext, mTestCallProfile);
+        assertFalse(mTestImsCall.isWifiCall());
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
+        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
+                ServiceState.RIL_RADIO_TECHNOLOGY_LTE + "");
+        assertFalse(mTestImsCall.isWifiCall());
+        assertEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
     }
 
     @Test
@@ -81,11 +105,11 @@
     public void testSetLteNoWifi() {
         ImsCall mTestImsCall = new ImsCall(mContext, mTestCallProfile);
         assertFalse(mTestImsCall.isWifiCall());
-        assertNotEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
-        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
-                ServiceState.RIL_RADIO_TECHNOLOGY_LTE + "");
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
+        mBundle.putInt(ImsCallProfile.EXTRA_CALL_NETWORK_TYPE,
+                TelephonyManager.NETWORK_TYPE_LTE);
         assertFalse(mTestImsCall.isWifiCall());
-        assertEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        assertEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
     }
 
     @Test
@@ -93,10 +117,10 @@
     public void testSetLteNoWifiAlt() {
         ImsCall mTestImsCall = new ImsCall(mContext, mTestCallProfile);
         assertFalse(mTestImsCall.isWifiCall());
-        assertNotEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        assertNotEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
         mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT,
                 ServiceState.RIL_RADIO_TECHNOLOGY_LTE + "");
         assertFalse(mTestImsCall.isWifiCall());
-        assertEquals(mTestImsCall.getRadioTechnology(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        assertEquals(mTestImsCall.getNetworkType(), TelephonyManager.NETWORK_TYPE_LTE);
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java
index 82c62dd..335f5a4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java
@@ -90,7 +90,6 @@
     }
 
     @FlakyTest
-    @Ignore
     @Test
     @SmallTest
     public void testConnectionDisconnected() {
@@ -106,6 +105,8 @@
         doReturn(Call.State.DISCONNECTED).when(mConnection2).getState();
         mImsCallUT.connectionDisconnected(null);
         assertEquals(Call.State.DISCONNECTED, mImsCallUT.getState());
+        mImsCallUT.onHangupLocal();
+        assertEquals(Call.State.DISCONNECTED, mImsCallUT.getState());
     }
 
     @FlakyTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 5914454..0a1d51c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.internal.telephony.imsphone;
 
+import static junit.framework.TestCase.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -33,6 +35,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -44,14 +47,12 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsCallSession;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsStreamMediaProfile;
-import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -88,7 +89,6 @@
 public class ImsPhoneCallTrackerTest extends TelephonyTest {
     private ImsPhoneCallTracker mCTUT;
     private MmTelFeature.Listener mMmTelListener;
-    private RegistrationManager.RegistrationCallback mRegistrationCallback;
     private ImsMmTelManager.CapabilityCallback mCapabilityCallback;
     private ImsCall.Listener mImsCallListener;
     private ImsCall mImsCall;
@@ -102,6 +102,8 @@
     private ImsPhoneConnection.Listener mImsPhoneConnectionListener;
     @Mock
     private ImsConfig mImsConfig;
+    @Mock
+    private ImsPhoneConnection mImsPhoneConnection;
 
     private void imsCallMocking(final ImsCall imsCall) throws Exception {
 
@@ -163,6 +165,7 @@
         mImsCall = spy(new ImsCall(mContext, mImsCallProfile));
         mSecondImsCall = spy(new ImsCall(mContext, mImsCallProfile));
         mImsPhoneConnectionListener = mock(ImsPhoneConnection.Listener.class);
+        mImsPhoneConnection = mock(ImsPhoneConnection.class);
         imsCallMocking(mImsCall);
         imsCallMocking(mSecondImsCall);
         doReturn(ImsFeature.STATE_READY).when(mImsManager).getImsServiceState();
@@ -197,12 +200,6 @@
                 (ImsCall.Listener) any());
 
         doAnswer(invocation -> {
-            mRegistrationCallback = invocation.getArgument(0);
-            return mRegistrationCallback;
-        }).when(mImsManager).addRegistrationCallback(
-                any(RegistrationManager.RegistrationCallback.class));
-
-        doAnswer(invocation -> {
             mCapabilityCallback = (ImsMmTelManager.CapabilityCallback) invocation.getArguments()[0];
             return mCapabilityCallback;
 
@@ -240,39 +237,6 @@
 
     @Test
     @SmallTest
-    public void testImsRegistered() {
-        // when IMS is registered
-        mRegistrationCallback.onRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
-        // then service state should be IN_SERVICE and ImsPhone state set to registered
-        verify(mImsPhone).setServiceState(eq(ServiceState.STATE_IN_SERVICE));
-        verify(mImsPhone).setImsRegistrationState(eq(
-                RegistrationManager.REGISTRATION_STATE_REGISTERED));
-    }
-
-    @Test
-    @SmallTest
-    public void testImsRegistering() {
-        // when IMS is registering
-        mRegistrationCallback.onRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
-        // then service state should be OUT_OF_SERVICE and ImsPhone state set to not registered
-        verify(mImsPhone).setServiceState(eq(ServiceState.STATE_OUT_OF_SERVICE));
-        verify(mImsPhone).setImsRegistrationState(eq(
-                RegistrationManager.REGISTRATION_STATE_REGISTERING));
-    }
-
-    @Test
-    @SmallTest
-    public void testImsDeregistered() {
-        // when IMS is deregistered
-        mRegistrationCallback.onUnregistered(new ImsReasonInfo());
-        // then service state should be OUT_OF_SERVICE and ImsPhone state set to not registered
-        verify(mImsPhone).setServiceState(eq(ServiceState.STATE_OUT_OF_SERVICE));
-        verify(mImsPhone).setImsRegistrationState(eq(
-                RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED));
-    }
-
-    @Test
-    @SmallTest
     public void testVowifiDisabledOnLte() {
         // LTE is registered.
         doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_LTE).when(
@@ -748,18 +712,18 @@
 
         // First handover from LTE to WIFI; this takes us into a mid-call state.
         call.getImsCallSessionListenerProxy().callSessionHandover(call.getCallSession(),
-                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+                TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_IWLAN,
                 new ImsReasonInfo());
         // Handover back to LTE.
         call.getImsCallSessionListenerProxy().callSessionHandover(call.getCallSession(),
-                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+                TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyManager.NETWORK_TYPE_LTE,
                 new ImsReasonInfo());
         verify(mImsPhoneConnectionListener).onConnectionEvent(eq(
                 TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE), isNull());
 
         // Finally hand back to WIFI
         call.getImsCallSessionListenerProxy().callSessionHandover(call.getCallSession(),
-                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+                TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_IWLAN,
                 new ImsReasonInfo());
         verify(mImsPhoneConnectionListener).onConnectionEvent(eq(
                 TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI), isNull());
@@ -966,6 +930,23 @@
 
     @Test
     @SmallTest
+    public void testMergeComplete() {
+        boolean[] result = new boolean[1];
+        // Place a call.
+        ImsPhoneConnection connection = placeCallAndMakeActive();
+        connection.addListener(new Connection.ListenerBase() {
+            @Override
+            public void onConnectionEvent(String event, Bundle extras) {
+                result[0] = android.telecom.Connection.EVENT_MERGE_COMPLETE.equals(event);
+            }
+        });
+        ImsCall call = connection.getImsCall();
+        call.getListener().onCallMerged(call, null, false);
+        assertTrue(result[0]);
+    }
+
+    @Test
+    @SmallTest
     public void testNumericOnlyRemap() {
         assertEquals(ImsReasonInfo.CODE_SIP_FORBIDDEN, mCTUT.maybeRemapReasonCode(
                 new ImsReasonInfo(ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE, 0)));
@@ -1005,7 +986,26 @@
                                 "SERVICE not allowed in this location")));
     }
 
-    private void placeCallAndMakeActive() {
+    @Test
+    @SmallTest
+    public void testNoHoldErrorMessageWhenCallDisconnected() {
+        when(mImsPhoneConnection.getImsCall()).thenReturn(mImsCall);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocationOnMock) {
+                fail("Error message showed when the call has already been disconnected!");
+                return null;
+            }
+        }).when(mImsPhoneConnection)
+                .onConnectionEvent(eq(android.telecom.Connection.EVENT_CALL_HOLD_FAILED), any());
+        mCTUT.getConnections().add(mImsPhoneConnection);
+        when(mImsPhoneConnection.getState()).thenReturn(ImsPhoneCall.State.DISCONNECTED);
+        ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_UNSPECIFIED,
+                ImsReasonInfo.CODE_UNSPECIFIED, null);
+        mCTUT.getImsCallListener().onCallHoldFailed(mImsPhoneConnection.getImsCall(), info);
+    }
+
+    private ImsPhoneConnection placeCallAndMakeActive() {
         try {
             doAnswer(new Answer<ImsCall>() {
                 @Override
@@ -1038,6 +1038,7 @@
                 new ImsStreamMediaProfile());
         imsCall.getImsCallSessionListenerProxy().callSessionStarted(imsCall.getSession(),
                 new ImsCallProfile());
+        return connection;
     }
 }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java
index 5050b89..1aa47d4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java
@@ -38,6 +38,7 @@
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -248,13 +249,26 @@
 
     @Test
     @SmallTest
+    public void testSetWifiDeprecated() {
+        mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+        assertFalse(mConnectionUT.isWifi());
+        // ImsCall.getRadioTechnology is tested elsewhere
+        doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsCall).getNetworkType();
+        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
+                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + "");
+        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
+        assertTrue(mConnectionUT.isWifi());
+    }
+
+    @Test
+    @SmallTest
     public void testSetWifi() {
         mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
         assertFalse(mConnectionUT.isWifi());
         // ImsCall.getRadioTechnology is tested elsewhere
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mImsCall).getRadioTechnology();
-        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
-                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + "");
+        doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsCall).getNetworkType();
+        mBundle.putString(ImsCallProfile.EXTRA_CALL_NETWORK_TYPE,
+                TelephonyManager.NETWORK_TYPE_IWLAN + "");
         assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
         assertTrue(mConnectionUT.isWifi());
     }
@@ -265,7 +279,7 @@
         mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
         assertFalse(mConnectionUT.isWifi());
         // ImsCall.getRadioTechnology is tested elsewhere
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mImsCall).getRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsCall).getNetworkType();
         // Tests to make sure that the EXTRA_CALL_RAT_TYPE_ALT string is set correctly for newer
         // devices.
         mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT,
@@ -276,13 +290,26 @@
 
     @Test
     @SmallTest
+    public void testSetLTEDeprecated() {
+        mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+        assertNotEquals(mConnectionUT.getCallRadioTech(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        // ImsCall.getRadioTechnology is tested elsewhere
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsCall).getNetworkType();
+        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
+                ServiceState.RIL_RADIO_TECHNOLOGY_LTE + "");
+        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
+        assertEquals(mConnectionUT.getCallRadioTech(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+    }
+
+    @Test
+    @SmallTest
     public void testSetLTE() {
         mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
         assertNotEquals(mConnectionUT.getCallRadioTech(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
         // ImsCall.getRadioTechnology is tested elsewhere
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mImsCall).getRadioTechnology();
-        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
-                ServiceState.RIL_RADIO_TECHNOLOGY_LTE + "");
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsCall).getNetworkType();
+        mBundle.putString(ImsCallProfile.EXTRA_CALL_NETWORK_TYPE,
+                TelephonyManager.NETWORK_TYPE_LTE + "");
         assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
         assertEquals(mConnectionUT.getCallRadioTech(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
     }
@@ -293,7 +320,7 @@
         mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
         assertNotEquals(mConnectionUT.getCallRadioTech(), ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
         // ImsCall.getRadioTechnology is tested elsewhere
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mImsCall).getRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsCall).getNetworkType();
         // Tests to make sure that the EXTRA_CALL_RAT_TYPE_ALT string is set correctly for newer
         // devices.
         mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index 0cdc34c..8aab248 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -50,13 +50,14 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PersistableBundle;
-import android.os.SystemProperties;
+import android.sysprop.TelephonyProperties;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.telephony.ims.stub.ImsUtImplBase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -64,7 +65,6 @@
 import androidx.test.filters.FlakyTest;
 
 import com.android.ims.ImsEcbmStateListener;
-import com.android.ims.ImsManager;
 import com.android.ims.ImsUtInterface;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
@@ -73,7 +73,6 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 
@@ -133,12 +132,12 @@
         doReturn(Call.State.IDLE).when(mRingingCall).getState();
         doReturn(mExecutor).when(mContext).getMainExecutor();
 
-        mContextFixture.putBooleanResource(com.android.internal.R.bool.config_voice_capable, true);
+        doReturn(true).when(mTelephonyManager).isVoiceCapable();
 
         mImsPhoneUT = new ImsPhone(mContext, mNotifier, mPhone, true);
 
-        mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
-                TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
+        mDoesRilSendMultipleCallRing = TelephonyProperties.ril_sends_multiple_call_ring()
+                .orElse(true);
         replaceInstance(Handler.class, "mLooper", mTestHandler, mImsPhoneUT.getLooper());
         replaceInstance(Phone.class, "mLooper", mPhone, mImsPhoneUT.getLooper());
         mImsPhoneUT.registerForSuppServiceNotification(mTestHandler,
@@ -220,11 +219,25 @@
         assertEquals(Phone.SuppService.SEPARATE,
                 ((AsyncResult) messageArgumentCaptor.getValue().obj).result);
 
-        // ringing call is idle
+        // ringing call is idle, only an active call present
+        doReturn(Call.State.ACTIVE).when(mForegroundCall).getState();
         assertEquals(true, mImsPhoneUT.handleInCallMmiCommands("2"));
         verify(mImsCT).holdActiveCall();
 
+        // background call is holding
+        doReturn(Call.State.HOLDING).when(mBackgroundCall).getState();
+        doReturn(Call.State.IDLE).when(mForegroundCall).getState();
+        assertEquals(true, mImsPhoneUT.handleInCallMmiCommands("2"));
+        verify(mImsCT).unholdHeldCall();
+
+        // background call is holding and there's an active foreground call
+        doReturn(Call.State.ACTIVE).when(mForegroundCall).getState();
+        assertEquals(true, mImsPhoneUT.handleInCallMmiCommands("2"));
+        verify(mImsCT, times(2)).holdActiveCall();
+
         // ringing call is not idle
+        doReturn(Call.State.IDLE).when(mForegroundCall).getState();
+        doReturn(Call.State.IDLE).when(mBackgroundCall).getState();
         doReturn(Call.State.INCOMING).when(mRingingCall).getState();
         assertEquals(true, mImsPhoneUT.handleInCallMmiCommands("2"));
         verify(mImsCT).acceptCall(ImsCallProfile.CALL_TYPE_VOICE);
@@ -521,22 +534,23 @@
                 CommandsInterface.SERVICE_CLASS_NONE);
 
         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
-        verify(mImsUtInterface).queryCallBarring(eq(ImsUtInterface.CB_BAOC),
+        verify(mImsUtInterface).queryCallBarring(eq(ImsUtImplBase.CALL_BARRING_ALL_OUTGOING),
                 messageArgumentCaptor.capture(), eq(CommandsInterface.SERVICE_CLASS_NONE));
         assertEquals(msg, messageArgumentCaptor.getValue().obj);
 
         mImsPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOIC, true, "abc", msg,
                 CommandsInterface.SERVICE_CLASS_NONE);
-        verify(mImsUtInterface).updateCallBarring(eq(ImsUtInterface.CB_BOIC),
+        verify(mImsUtInterface).updateCallBarring(eq(ImsUtImplBase.CALL_BARRING_OUTGOING_INTL),
                 eq(CommandsInterface.CF_ACTION_ENABLE), messageArgumentCaptor.capture(),
-                (String[]) eq(null), eq(CommandsInterface.SERVICE_CLASS_NONE));
+                (String[]) eq(null), eq(CommandsInterface.SERVICE_CLASS_NONE), eq("abc"));
         assertEquals(msg, messageArgumentCaptor.getValue().obj);
 
         mImsPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOICxH, false, "abc", msg,
                 CommandsInterface.SERVICE_CLASS_NONE);
-        verify(mImsUtInterface).updateCallBarring(eq(ImsUtInterface.CB_BOIC_EXHC),
+        verify(mImsUtInterface).updateCallBarring(
+                eq(ImsUtImplBase.CALL_BARRING_OUTGOING_INTL_EXCL_HOME),
                 eq(CommandsInterface.CF_ACTION_DISABLE), messageArgumentCaptor.capture(),
-                (String[])eq(null), eq(CommandsInterface.SERVICE_CLASS_NONE));
+                (String[]) eq(null), eq(CommandsInterface.SERVICE_CLASS_NONE), eq("abc"));
         assertEquals(msg, messageArgumentCaptor.getValue().obj);
     }
 
@@ -608,15 +622,14 @@
         assertEquals(false, mImsPhoneUT.getWakeLock().isHeld());
     }
 
-    @FlakyTest
     @Test
     @SmallTest
-    @Ignore
     public void testProcessDisconnectReason() throws Exception {
         // set up CarrierConfig
         PersistableBundle bundle = mContextFixture.getCarrierConfigBundle();
         bundle.putStringArray(CarrierConfigManager.KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY,
                 new String[]{"REG09|0"});
+        doReturn(true).when(mImsManager).isWfcEnabledByUser();
 
         // set up overlays
         String title = "title";
@@ -633,18 +646,17 @@
         mImsPhoneUT.processDisconnectReason(
                 new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 0, "REG09"));
 
-        // TODO: Verify that WFC has been turned off (can't do it right now because
-        // setWfcSetting is static).
-        //verify(mImsManager).setWfcSetting(any(), eq(false));
-
         ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
         verify(mContext).sendOrderedBroadcast(
                 intent.capture(), nullable(String.class), any(BroadcastReceiver.class),
                 nullable(Handler.class), eq(Activity.RESULT_OK), nullable(String.class),
                 nullable(Bundle.class));
-        assertEquals(ImsManager.ACTION_IMS_REGISTRATION_ERROR, intent.getValue().getAction());
-        assertEquals(title, intent.getValue().getStringExtra(Phone.EXTRA_KEY_ALERT_TITLE));
-        assertEquals(messageAlert, intent.getValue().getStringExtra(Phone.EXTRA_KEY_ALERT_MESSAGE));
+        assertEquals(android.telephony.ims.ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR,
+                intent.getValue().getAction());
+        assertEquals(title, intent.getValue().getStringExtra(
+                android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_TITLE));
+        assertEquals(messageAlert, intent.getValue().getStringExtra(
+                android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE));
         assertEquals(messageNotification,
                 intent.getValue().getStringExtra(Phone.EXTRA_KEY_NOTIFICATION_MESSAGE));
     }
@@ -691,6 +703,8 @@
         assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED, regResult.intValue());
     }
 
+    @Test
+    @SmallTest
     public void testGetImsRegistrationTech() throws Exception {
         LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(1);
         Consumer<Integer> regTechCallback = queue::offer;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java
new file mode 100644
index 0000000..f2f69db
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 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.imsphone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.verify;
+
+import android.net.Uri;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.RegistrationManager.RegistrationCallback;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.imsphone.ImsRegistrationCallbackHelper.ImsRegistrationUpdate;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public class ImsRegistrationCallbackHelperTest extends TelephonyTest {
+
+    @Mock
+    private ImsRegistrationUpdate mMockRegistrationUpdate;
+    private ImsRegistrationCallbackHelper mRegistrationCallbackHelper;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp(getClass().getSimpleName());
+
+        mRegistrationCallbackHelper = new ImsRegistrationCallbackHelper(mMockRegistrationUpdate,
+                Runnable::run);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+        mRegistrationCallbackHelper = null;
+    }
+
+    @Test
+    @SmallTest
+    public void testRegistrationStateReset() {
+        // When reset is called
+        mRegistrationCallbackHelper.reset();
+
+        // The registration state should be equal to REGISTRATION_STATE_NOT_REGISTERED
+        assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED,
+                mRegistrationCallbackHelper.getImsRegistrationState());
+    }
+
+    @Test
+    @SmallTest
+    public void testRegistrationStateUpdate() {
+        // Verify Registration state can be update to NOT registered correctly.
+        int state = RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED;
+        mRegistrationCallbackHelper.updateRegistrationState(state);
+
+        assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED,
+                mRegistrationCallbackHelper.getImsRegistrationState());
+
+        // Verify Registration state can be update to registering correctly.
+        state = RegistrationManager.REGISTRATION_STATE_REGISTERING;
+        mRegistrationCallbackHelper.updateRegistrationState(state);
+
+        assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERING,
+                mRegistrationCallbackHelper.getImsRegistrationState());
+
+        // Verify Registration state can be update to registered correctly.
+        state = RegistrationManager.REGISTRATION_STATE_REGISTERED;
+        mRegistrationCallbackHelper.updateRegistrationState(state);
+
+        assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERED,
+                mRegistrationCallbackHelper.getImsRegistrationState());
+    }
+
+    @Test
+    @SmallTest
+    public void testIsImsRegistered() {
+        // When the registration state is not registered
+        mRegistrationCallbackHelper.updateRegistrationState(
+                RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
+
+        // The result of isImsRegistered should be false
+        assertFalse(mRegistrationCallbackHelper.isImsRegistered());
+
+        // When the registration state is not registered
+        mRegistrationCallbackHelper.updateRegistrationState(
+                RegistrationManager.REGISTRATION_STATE_REGISTERED);
+
+        // The result of isImsRegistered should be true
+        assertTrue(mRegistrationCallbackHelper.isImsRegistered());
+    }
+
+    @Test
+    @SmallTest
+    public void testImsOnRegistered() {
+        // Verify the RegistrationCallback should not be null
+        RegistrationCallback callback = mRegistrationCallbackHelper.getCallback();
+        assertNotNull(callback);
+
+        // When onRegistered is called, the registration state should be
+        // REGISTRATION_STATE_REGISTERED
+        callback.onRegistered(AccessNetworkType.IWLAN);
+
+        assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERED,
+                mRegistrationCallbackHelper.getImsRegistrationState());
+        verify(mMockRegistrationUpdate).handleImsRegistered(anyInt());
+    }
+
+    @Test
+    @SmallTest
+    public void testImsOnRegistering() {
+        // Verify the RegistrationCallback should not be null
+        RegistrationCallback callback = mRegistrationCallbackHelper.getCallback();
+        assertNotNull(callback);
+
+        // When onRegistering is called, the registration state should be
+        // REGISTRATION_STATE_REGISTERING
+        callback.onRegistering(AccessNetworkType.IWLAN);
+        // The registration state should be REGISTRATION_STATE_REGISTERING
+        assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERING,
+                mRegistrationCallbackHelper.getImsRegistrationState());
+        verify(mMockRegistrationUpdate).handleImsRegistering(anyInt());
+    }
+
+    @Test
+    @SmallTest
+    public void testImsUnRegistered() {
+        // Verify the RegistrationCallback should not be null
+        RegistrationCallback callback = mRegistrationCallbackHelper.getCallback();
+        assertNotNull(callback);
+
+        // When onUnregistered is called, the registration state should be
+        // REGISTRATION_STATE_NOT_REGISTERED
+        ImsReasonInfo reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 0);
+        callback.onUnregistered(reasonInfo);
+        // The registration state should be REGISTRATION_STATE_NOT_REGISTERED
+        assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED,
+                mRegistrationCallbackHelper.getImsRegistrationState());
+        verify(mMockRegistrationUpdate).handleImsUnregistered(reasonInfo);
+    }
+
+    @Test
+    @SmallTest
+    public void testSubscriberAssociatedUriChanged() {
+        // Verify the RegistrationCallback should not be null
+        RegistrationCallback callback = mRegistrationCallbackHelper.getCallback();
+        assertNotNull(callback);
+
+        // When onSubscriberAssociatedUriChanged is called
+        Uri[] uris = new Uri[0];
+        callback.onSubscriberAssociatedUriChanged(uris);
+        // The handleImsSubscriberAssociatedUriChanged should be called
+        verify(mMockRegistrationUpdate).handleImsSubscriberAssociatedUriChanged(uris);
+    }
+}
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..a82803e 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;
 
@@ -35,8 +37,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
 
+import android.net.InetAddresses;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
+import android.net.NetworkCapabilities;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
@@ -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
@@ -280,7 +284,8 @@
                 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
                 EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
 
-        mMetrics.writeEmergencyNumberUpdateEvent(mPhone.getPhoneId(), number);
+        mMetrics.writeEmergencyNumberUpdateEvent(mPhone.getPhoneId(), number,
+                TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION);
         TelephonyLog log = buildProto();
 
         assertEquals(1, log.events.length);
@@ -298,6 +303,34 @@
                 log.events[0].updatedEmergencyNumber.numberSourcesBitmask);
         assertEquals(EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL,
                 log.events[0].updatedEmergencyNumber.routing);
+        assertEquals(TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION,
+                log.events[0].emergencyNumberDatabaseVersion);
+    }
+
+    // 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
@@ -470,19 +503,22 @@
     @Test
     @SmallTest
     public void testWriteOnSetupDataCallResponse() throws Exception {
-        DataCallResponse response = new DataCallResponse(
-                5, /* status */
-                6, /* suggestedRetryTime */
-                7, /* cid */
-                8, /* active */
-                ApnSetting.PROTOCOL_IPV4V6, /* protocolType */
-                FAKE_IFNAME, /* ifname */
-                Arrays.asList(new LinkAddress(
-                       NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)), /* addresses */
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)), /* dnses */
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)), /* gateways */
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_PCSCF_ADDRESS)), /* pcscfs */
-                1440 /* mtu */);
+        DataCallResponse response = new DataCallResponse.Builder()
+                .setCause(5)
+                .setSuggestedRetryTime(6)
+                .setId(7)
+                .setLinkStatus(8)
+                .setProtocolType(ApnSetting.PROTOCOL_IPV4V6)
+                .setInterfaceName(FAKE_IFNAME)
+                .setAddresses(Arrays.asList(
+                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
+                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
+                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
+                .setPcscfAddresses(
+                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
+                .setMtuV4(1440)
+                .setMtuV6(1440)
+                .build();
 
         mMetrics.writeOnRilSolicitedResponse(mPhone.getPhoneId(), 1, 2,
                 RIL_REQUEST_SETUP_DATA_CALL, response);
@@ -675,17 +711,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 +759,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);
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
deleted file mode 100644
index 485a8aa..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright (C) 2008 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.mocks;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
-import android.net.NetworkFactory;
-import android.net.NetworkInfo;
-import android.net.NetworkMisc;
-import android.net.NetworkRequest;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
-import com.android.server.connectivity.NetworkAgentInfo;
-
-import java.util.HashMap;
-
-public class ConnectivityServiceMock {
-    private static final String TAG = "ConnectivityServiceMock";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = true;
-
-    /**
-     * used internally when registering NetworkFactories
-     * obj = NetworkFactoryInfo
-     */
-    private static final int EVENT_REGISTER_NETWORK_FACTORY = 17;
-
-    /**
-     * used internally when registering NetworkAgents
-     * obj = Messenger
-     */
-    private static final int EVENT_REGISTER_NETWORK_AGENT = 18;
-
-    /**
-     * used to add a network request
-     * includes a NetworkRequestInfo
-     */
-    private static final int EVENT_REGISTER_NETWORK_REQUEST = 19;
-
-    /**
-     * used to add a network listener - no request
-     * includes a NetworkRequestInfo
-     */
-    private static final int EVENT_REGISTER_NETWORK_LISTENER = 21;
-
-    /**
-     * used to remove a network request, either a listener or a real request
-     * arg1 = UID of caller
-     * obj  = NetworkRequest
-     */
-    private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
-
-    /**
-     * used internally when registering NetworkFactories
-     * obj = Messenger
-     */
-    private static final int EVENT_UNREGISTER_NETWORK_FACTORY = 23;
-
-
-    private final HandlerThread mHandlerThread;
-    /** Handler used for internal events. */
-    final private InternalHandler mHandler;
-    /** Handler used for incoming {@link NetworkStateTracker} events. */
-    final private NetworkStateTrackerHandler mTrackerHandler;
-
-    final private Context mContext;
-
-    public ConnectivityServiceMock(Context context) {
-        if (DBG) log("starting up");
-
-        mContext = context;
-        mHandlerThread = new HandlerThread("ConnectivityServiceMock");
-        mHandlerThread.start();
-        mHandler = new InternalHandler(mHandlerThread.getLooper());
-        mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
-    }
-
-    public void die() {
-        // clean up threads/handlers
-        if (mHandlerThread != null) {
-            mHandlerThread.quit();
-        }
-    }
-
-    public HandlerThread getHandlerThread() {
-        return mHandlerThread;
-    }
-
-    private class InternalHandler extends Handler {
-        public InternalHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case EVENT_REGISTER_NETWORK_FACTORY: {
-                    handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
-                    break;
-                }
-                case EVENT_UNREGISTER_NETWORK_FACTORY: {
-                    handleUnregisterNetworkFactory((Messenger)msg.obj);
-                    break;
-                }
-                case EVENT_REGISTER_NETWORK_AGENT: {
-                    handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
-                    break;
-                }
-                case EVENT_REGISTER_NETWORK_REQUEST:
-                case EVENT_REGISTER_NETWORK_LISTENER: {
-                    handleRegisterNetworkRequest((NetworkRequestInfo) msg.obj);
-                    break;
-                }
-                case EVENT_RELEASE_NETWORK_REQUEST: {
-                    handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1);
-                    break;
-                }
-            }
-        }
-    }
-
-    private class NetworkStateTrackerHandler extends Handler {
-        public NetworkStateTrackerHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            NetworkInfo info;
-            switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
-                    handleAsyncChannelHalfConnect(msg);
-                    break;
-                }
-                case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
-                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
-                    if (nai != null) nai.asyncChannel.disconnect();
-                    break;
-                }
-                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
-                    handleAsyncChannelDisconnected(msg);
-                    break;
-                }
-            }
-        }
-    }
-
-    private boolean isRequest(NetworkRequest request) {
-        return mNetworkRequests.get(request).isRequest;
-    }
-
-    private void handleAsyncChannelHalfConnect(Message msg) {
-        AsyncChannel ac = (AsyncChannel) msg.obj;
-        if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
-            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                if (VDBG) log("NetworkFactory connected");
-                // A network factory has connected.  Send it all current NetworkRequests.
-                for (NetworkRequestInfo nri : mNetworkRequests.values()) {
-                    if (nri.isRequest == false) continue;
-                    //NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
-                    NetworkAgentInfo nai = null;
-                    ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
-                            (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
-                }
-            } else {
-                loge("Error connecting NetworkFactory");
-                mNetworkFactoryInfos.remove(msg.obj);
-            }
-        } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
-            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                if (VDBG) log("NetworkAgent connected");
-                // A network agent has requested a connection.  Establish the connection.
-                mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
-                        sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
-            } else {
-                loge("Error connecting NetworkAgent");
-                NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
-                //if (nai != null) {
-                //    final boolean wasDefault = isDefaultNetwork(nai);
-                //    synchronized (mNetworkForNetId) {
-                //        mNetworkForNetId.remove(nai.network.netId);
-                //        mNetIdInUse.delete(nai.network.netId);
-                //    }
-                //    // Just in case.
-                //    mLegacyTypeTracker.remove(nai, wasDefault);
-                //}
-            }
-        }
-    }
-
-    private void handleAsyncChannelDisconnected(Message msg) {
-        NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
-        if (nai != null) {
-            if (DBG) {
-                log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
-            }
-            // A network agent has disconnected.
-            // TODO - if we move the logic to the network agent (have them disconnect
-            // because they lost all their requests or because their score isn't good)
-            // then they would disconnect organically, report their new state and then
-            // disconnect the channel.
-            //if (nai.networkInfo.isConnected()) {
-            //    nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
-            //            null, null);
-            //}
-            //final boolean wasDefault = isDefaultNetwork(nai);
-            //if (wasDefault) {
-            //    mDefaultInetConditionPublished = 0;
-            //}
-            //notifyIfacesChanged();
-            // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
-            // by other networks that are already connected. Perhaps that can be done by
-            // sending all CALLBACK_LOST messages (for requests, not listens) at the end
-            // of rematchAllNetworksAndRequests
-            //notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
-            //mKeepaliveTracker.handleStopAllKeepalives(nai,
-            //       ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
-            // nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
-            mNetworkAgentInfos.remove(msg.replyTo);
-            //updateClat(null, nai.linkProperties, nai);
-            //synchronized (mNetworkForNetId) {
-            //    // Remove the NetworkAgent, but don't mark the netId as
-            //    // available until we've told netd to delete it below.
-            //    mNetworkForNetId.remove(nai.network.netId);
-            //}
-            // Remove all previously satisfied requests.
-            //for (int i = 0; i < nai.networkRequests.size(); i++) {
-            //    NetworkRequest request = nai.networkRequests.valueAt(i);
-            //    NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
-            //    if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
-            //        mNetworkForRequestId.remove(request.requestId);
-            //        sendUpdatedScoreToFactories(request, 0);
-            //    }
-            //}
-            //if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
-            //    removeDataActivityTracking(nai);
-            //    notifyLockdownVpn(nai);
-            //    requestNetworkTransitionWakelock(nai.name());
-            //}
-            //mLegacyTypeTracker.remove(nai, wasDefault);
-            //rematchAllNetworksAndRequests(null, 0);
-            //if (nai.created) {
-            //    // Tell netd to clean up the configuration for this network
-            //    // (routing rules, DNS, etc).
-            //    // This may be slow as it requires a lot of netd shelling out to ip and
-            //    // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
-            //    // after we've rematched networks with requests which should make a potential
-            //    // fallback network the default or requested a new network from the
-            //    // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
-            //    // long time.
-            //    try {
-            //        mNetd.removeNetwork(nai.network.netId);
-            //    } catch (Exception e) {
-            //        loge("Exception removing network: " + e);
-            //    }
-            //}
-            //synchronized (mNetworkForNetId) {
-            //    mNetIdInUse.delete(nai.network.netId);
-            //}
-        } else {
-            NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(msg.replyTo);
-            if (DBG && nfi != null) log("unregisterNetworkFactory for " + nfi.name);
-        }
-    }
-
-    private void log(String str) {
-        Slog.d(TAG, str);
-    }
-    private void loge(String str) {
-        Slog.e(TAG, str);
-    }
-
-    // NetworkAgentInfo keyed off its connecting messenger
-    // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
-    // NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
-    private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
-            new HashMap<Messenger, NetworkAgentInfo>();
-    private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
-            new HashMap<Messenger, NetworkFactoryInfo>();
-    private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
-            new HashMap<NetworkRequest, NetworkRequestInfo>();
-
-    private static class NetworkFactoryInfo {
-        public final String name;
-        public final Messenger messenger;
-        public final AsyncChannel asyncChannel;
-        public final int factorySerialNumber;
-
-        NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
-                int factorySerialNumber) {
-            this.name = name;
-            this.messenger = messenger;
-            this.asyncChannel = asyncChannel;
-            this.factorySerialNumber = factorySerialNumber;
-        }
-    }
-
-    private int getCallingUid() {
-        return Process.myUid();
-    }
-
-    private int getCallingPid() {
-        return Process.myPid();
-    }
-
-    private class NetworkRequestInfo implements IBinder.DeathRecipient {
-        static final boolean REQUEST = true;
-        static final boolean LISTEN = false;
-
-        final NetworkRequest request;
-        final PendingIntent mPendingIntent;
-        boolean mPendingIntentSent;
-        private final IBinder mBinder;
-        final int mPid;
-        final int mUid;
-        final Messenger messenger;
-        final boolean isRequest;
-
-        NetworkRequestInfo(NetworkRequest r, PendingIntent pi, boolean isRequest) {
-            request = r;
-            mPendingIntent = pi;
-            messenger = null;
-            mBinder = null;
-            mPid = getCallingPid();
-            mUid = getCallingUid();
-            this.isRequest = isRequest;
-        }
-
-        NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) {
-            super();
-            messenger = m;
-            request = r;
-            mBinder = binder;
-            mPid = getCallingPid();
-            mUid = getCallingUid();
-            this.isRequest = isRequest;
-            mPendingIntent = null;
-
-            try {
-                mBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                binderDied();
-            }
-        }
-
-        void unlinkDeathRecipient() {
-            if (mBinder != null) {
-                mBinder.unlinkToDeath(this, 0);
-            }
-        }
-
-        public void binderDied() {
-            log("ConnectivityService NetworkRequestInfo binderDied(" +
-                    request + ", " + mBinder + ")");
-            releaseNetworkRequest(request);
-        }
-
-        public String toString() {
-            return (isRequest ? "Request" : "Listen") +
-                    " from uid/pid:" + mUid + "/" + mPid +
-                    " for " + request +
-                    (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
-        }
-    }
-
-
-    // sequence number of NetworkRequests
-    private int mNextNetworkRequestId = 1;
-    private synchronized int nextNetworkRequestId() {
-        return mNextNetworkRequestId++;
-    }
-
-    public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
-            Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
-        networkCapabilities = new NetworkCapabilities(networkCapabilities);
-
-        if (timeoutMs < 0) {
-            throw new IllegalArgumentException("Bad timeout specified");
-        }
-
-        NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
-                nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
-        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, true);
-        if (DBG) log("requestNetwork for " + nri);
-
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
-
-        return networkRequest;
-    }
-
-    public void releaseNetworkRequest(NetworkRequest networkRequest) {
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(),
-                0, networkRequest));
-    }
-
-    public int registerNetworkFactory(Messenger messenger, String name) {
-        NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
-                NetworkFactory.SerialNumber.nextSerialNumber());
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
-        return nfi.factorySerialNumber;
-    }
-
-    private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
-        if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
-        mNetworkFactoryInfos.put(nfi.messenger, nfi);
-        nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
-    }
-
-    public void unregisterNetworkFactory(Messenger messenger) {
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
-    }
-
-    private void handleUnregisterNetworkFactory(Messenger messenger) {
-        NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger);
-        if (nfi == null) {
-            loge("Failed to find Messenger in unregisterNetworkFactory");
-            return;
-        }
-        if (DBG) log("unregisterNetworkFactory for " + nfi.name);
-    }
-
-    public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
-            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
-            int currentScore, NetworkMisc networkMisc, int factorySerialNumber) {
-//        final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
-//                new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(
-//                linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,
-//                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
-//        synchronized (this) {
-//            nai.networkMonitor.systemReady = mSystemReady;
-//        }
-//        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
-//        return nai.network.netId;
-        throw new RuntimeException("not implemented");
-    }
-
-    private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
-        if (VDBG) log("Got NetworkAgent Messenger");
-//        mNetworkAgentInfos.put(na.messenger, na);
-//        synchronized (mNetworkForNetId) {
-//            mNetworkForNetId.put(na.network.netId, na);
-//        }
-//        na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
-//        NetworkInfo networkInfo = na.networkInfo;
-//        na.networkInfo = null;
-//        updateNetworkInfo(na, networkInfo);
-    }
-
-
-    private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
-        mNetworkRequests.put(nri.request, nri);
-        if (!nri.isRequest) {
-            for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
-                if (nri.request.networkCapabilities.hasSignalStrength() &&
-                        network.satisfiesImmutableCapabilitiesOf(nri.request)) {
-                }
-            }
-        }
-        rematchAllNetworksAndRequests(null, 0);
-        if (nri.isRequest) {
-            sendUpdatedScoreToFactories(nri.request, 0);
-        }
-    }
-
-    private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
-        NetworkRequestInfo nri = mNetworkRequests.get(request);
-        if (nri != null) {
-            if (DBG) log("releasing NetworkRequest " + request);
-            nri.unlinkDeathRecipient();
-            mNetworkRequests.remove(request);
-            if (nri.isRequest) {
-                // Find all networks that are satisfying this request and remove the request
-                // from their request lists.
-                // TODO - it's my understanding that for a request there is only a single
-                // network satisfying it, so this loop is wasteful
-                //boolean wasKept = false;
-                //for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                //    if (nai.networkRequests.get(nri.request.requestId) != null) {
-                //        nai.networkRequests.remove(nri.request.requestId);
-                //        if (DBG) {
-                //            log(" Removing from current network " + nai.name() +
-                //                    ", leaving " + nai.networkRequests.size() +
-                //                    " requests.");
-                //        }
-                //        if (unneeded(nai)) {
-                //            if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
-                //            teardownUnneededNetwork(nai);
-                //        } else {
-                //            // suspect there should only be one pass through here
-                //            // but if any were kept do the check below
-                //            wasKept |= true;
-                //        }
-                //    }
-                //}
-
-                //NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
-                //if (nai != null) {
-                //    mNetworkForRequestId.remove(nri.request.requestId);
-                //}
-                // Maintain the illusion.  When this request arrived, we might have pretended
-                // that a network connected to serve it, even though the network was already
-                // connected.  Now that this request has gone away, we might have to pretend
-                // that the network disconnected.  LegacyTypeTracker will generate that
-                // phantom disconnect for this type.
-                //if (nri.request.legacyType != TYPE_NONE && nai != null) {
-                //    boolean doRemove = true;
-                //    if (wasKept) {
-                //        // check if any of the remaining requests for this network are for the
-                //        // same legacy type - if so, don't remove the nai
-                //        for (int i = 0; i < nai.networkRequests.size(); i++) {
-                //            NetworkRequest otherRequest = nai.networkRequests.valueAt(i);
-                //            if (otherRequest.legacyType == nri.request.legacyType &&
-                //                    isRequest(otherRequest)) {
-                //                if (DBG) log(" still have other legacy request - leaving");
-                //                doRemove = false;
-                //            }
-                //        }
-                //    }
-                //
-                //    if (doRemove) {
-                //        mLegacyTypeTracker.remove(nri.request.legacyType, nai, false);
-                //    }
-                //}
-
-                for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
-                    nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST,
-                            nri.request);
-                }
-            } else {
-                // listens don't have a singular affectedNetwork.  Check all networks to see
-                // if this listen request applies and remove it.
-                //for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                //    nai.networkRequests.remove(nri.request.requestId);
-                //    if (nri.request.networkCapabilities.hasSignalStrength() &&
-                //            nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
-                //        updateSignalStrengthThresholds(nai, "RELEASE", nri.request);
-                //    }
-                //}
-            }
-            //callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
-        }
-    }
-
-    private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
-        for (int i = 0; i < nai.numNetworkRequests(); i++) {
-            NetworkRequest nr = nai.requestAt(i);
-            // Don't send listening requests to factories. b/17393458
-            if (!isRequest(nr)) continue;
-                sendUpdatedScoreToFactories(nr, nai.getCurrentScore());
-        }
-    }
-
-    private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
-        if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
-        for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
-            nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0,
-                    networkRequest);
-        }
-    }
-
-    private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
-    }
-
-    @VisibleForTesting
-    public NetworkRequest defaultRequest = null;
-    @VisibleForTesting
-    public synchronized void addDefaultRequest() {
-        if (defaultRequest != null) return;
-        NetworkCapabilities netCap = new NetworkCapabilities();
-        netCap.addCapability(NET_CAPABILITY_INTERNET);
-        netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
-        defaultRequest = requestNetwork(netCap, null, 0, new Binder(),
-                ConnectivityManager.TYPE_NONE);
-    }
-
-    @VisibleForTesting
-    public synchronized void setCurrentScoreForRequest(NetworkRequest nr, int score) {
-        sendUpdatedScoreToFactories(nr, score);
-    }
-
-    @VisibleForTesting
-    public synchronized void removeDefaultRequest() {
-        if (defaultRequest == null) return;
-        releaseNetworkRequest(defaultRequest);
-        defaultRequest = null;
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
deleted file mode 100644
index 0ce58c2..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
+++ /dev/null
@@ -1,1352 +0,0 @@
-/*
- * 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 android.content.Context;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.ResultReceiver;
-import android.os.WorkSource;
-import android.service.carrier.CarrierIdentifier;
-import android.telephony.CellInfo;
-import android.telephony.CellLocation;
-import android.telephony.DataConnectionRealTimeInfo;
-import android.telephony.NetworkScanRequest;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.VoLteServiceState;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.test.SimulatedRadioControl;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
-import com.android.internal.telephony.uicc.IccFileHandler;
-import com.android.internal.telephony.uicc.IsimRecords;
-import com.android.internal.telephony.uicc.UiccCard;
-import com.android.internal.telephony.uicc.UsimServiceTable;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * (<em>Not for SDK use</em>)
- * A base implementation for the com.android.internal.telephony.Phone interface.
- *
- * Note that implementations of Phone.java are expected to be used
- * from a single application thread. This should be the same thread that
- * originally called PhoneFactory to obtain the interface.
- *
- *  {@hide}
- *
- */
-
-public class PhoneMock extends Phone {
-    private static final String LOG_TAG = "PhoneMock";
-
-    protected PhoneMock(String name, PhoneNotifier notifier, Context context, CommandsInterface ci,
-            boolean unitTestMode) {
-        super(name, notifier, context, ci, unitTestMode);
-        throw new RuntimeException("not implemented");
-    }
-
-    protected PhoneMock(String name, PhoneNotifier notifier, Context context, CommandsInterface ci,
-            boolean unitTestMode, int phoneId,
-            TelephonyComponentFactory telephonyComponentFactory) {
-        super(name, notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getPhoneName() {
-        throw new RuntimeException("not implemented");
-    }
-
-    protected void setPhoneName(String name) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getNai(){
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getActionDetached() {
-        return "phonemock.action.detached.not.implemented";
-    }
-
-    public String getActionAttached() {
-        return "phonemock.action.attached.not.implemented";
-    }
-
-    public void setSystemProperty(String property, String value) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getSystemProperty(String property, String defValue) {
-        throw new RuntimeException("not implemented");
-    }
-
-    protected final RegistrantList mPreciseCallStateRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mHandoverRegistrants
-             = new RegistrantList();
-
-    protected final RegistrantList mRedialRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mNewRingingConnectionRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mIncomingRingRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mDisconnectRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mServiceStateRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mMmiCompleteRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mMmiRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mUnknownConnectionRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mSuppServiceFailedRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mRadioOffOrNotAvailableRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mSimRecordsLoadedRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mVideoCapabilityChangedRegistrants
-            = new RegistrantList();
-
-    protected final RegistrantList mEmergencyCallToggledRegistrants
-            = new RegistrantList();
-
-
-    public void startMonitoringImsService() {
-        throw new RuntimeException("not implemented");
-    }
-
-    @Override
-    public void handleMessage(Message msg) {
-        throw new RuntimeException("not implemented");
-    }
-
-    @Override
-    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public ArrayList<Connection> getHandoverConnection() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifySrvccState(Call.SrvccState state) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForSilentRedial(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForSilentRedial(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public Context getContext() {
-        return mContext;
-    }
-
-    protected void onUpdateIccAvailability() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void disableDnsCheck(boolean b) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isDnsCheckDisabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
-        mPreciseCallStateRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForPreciseCallStateChanged(Handler h) {
-        mPreciseCallStateRegistrants.remove(h);
-    }
-
-    protected void notifyPreciseCallStateChangedP() {
-        AsyncResult ar = new AsyncResult(null, this, null);
-        mPreciseCallStateRegistrants.notifyRegistrants(ar);
-
-        mNotifier.notifyPreciseCallState(this);
-    }
-
-    public void registerForHandoverStateChanged(Handler h, int what, Object obj) {
-        mHandoverRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForHandoverStateChanged(Handler h) {
-        mHandoverRegistrants.remove(h);
-    }
-
-    public void notifyHandoverStateChanged(Connection cn) {
-       AsyncResult ar = new AsyncResult(null, cn, null);
-       mHandoverRegistrants.notifyRegistrants(ar);
-    }
-
-    public void registerForRedialConnectionChanged(Handler h, int what, Object obj) {
-        mRedialRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForRedialConnectionChanged(Handler h) {
-        mRedialRegistrants.remove(h);
-    }
-
-    public void notifyRedialConnectionChanged(Connection cn) {
-        AsyncResult ar = new AsyncResult(null, cn, null);
-        mRedialRegistrants.notifyRegistrants(ar);
-    }
-
-    public void migrateFrom(Phone from) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void migrate(RegistrantList to, RegistrantList from) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForUnknownConnection(Handler h, int what, Object obj) {
-        mUnknownConnectionRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForUnknownConnection(Handler h) {
-        mUnknownConnectionRegistrants.remove(h);
-    }
-
-    public void registerForNewRingingConnection(
-            Handler h, int what, Object obj) {
-        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForNewRingingConnection(Handler h) {
-        mNewRingingConnectionRegistrants.remove(h);
-    }
-
-    public void registerForVideoCapabilityChanged(
-            Handler h, int what, Object obj) {
-        mVideoCapabilityChangedRegistrants.addUnique(h, what, obj);
-        notifyForVideoCapabilityChanged(mIsVideoCapable);
-    }
-
-    public void unregisterForVideoCapabilityChanged(Handler h) {
-        mVideoCapabilityChangedRegistrants.remove(h);
-    }
-
-    public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForInCallVoicePrivacyOn(Handler h){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForInCallVoicePrivacyOff(Handler h){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForIncomingRing(
-            Handler h, int what, Object obj) {
-        mIncomingRingRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForIncomingRing(Handler h) {
-        mIncomingRingRegistrants.remove(h);
-    }
-
-    public void registerForDisconnect(Handler h, int what, Object obj) {
-        mDisconnectRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForDisconnect(Handler h) {
-        mDisconnectRegistrants.remove(h);
-    }
-
-    public void registerForSuppServiceFailed(Handler h, int what, Object obj) {
-        mSuppServiceFailedRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForSuppServiceFailed(Handler h) {
-        mSuppServiceFailedRegistrants.remove(h);
-    }
-
-    public void registerForMmiInitiate(Handler h, int what, Object obj) {
-        mMmiRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForMmiInitiate(Handler h) {
-        mMmiRegistrants.remove(h);
-    }
-
-    public void registerForMmiComplete(Handler h, int what, Object obj) {
-        mMmiCompleteRegistrants.addUnique(h, what, obj);
-    }
-
-    public void unregisterForMmiComplete(Handler h) {
-        mMmiCompleteRegistrants.remove(h);
-    }
-
-    public void registerForSimRecordsLoaded(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForSimRecordsLoaded(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForTtyModeReceived(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForTtyModeReceived(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setNetworkSelectionModeAutomatic(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getNetworkSelectionMode(Message message) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void selectNetworkManually(OperatorInfo network, boolean persistSelection,
-            Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForEmergencyCallToggle(Handler h, int what, Object obj) {
-        Registrant r = new Registrant(h, what, obj);
-        mEmergencyCallToggledRegistrants.add(r);
-    }
-
-    public void unregisterForEmergencyCallToggle(Handler h) {
-        mEmergencyCallToggledRegistrants.remove(h);
-    }
-
-    public void restoreSavedNetworkSelection(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void saveClirSetting(int commandInterfaceCLIRMode) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForServiceStateChanged(Handler h, int what, Object obj) {
-        mServiceStateRegistrants.add(h, what, obj);
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForServiceStateChanged(Handler h) {
-        mServiceStateRegistrants.remove(h);
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForRingbackTone(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForRingbackTone(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForOnHoldTone(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForOnHoldTone(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForResendIncallMute(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForResendIncallMute(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setEchoSuppressionEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public SimulatedRadioControl getSimulatedRadioControl() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public PhoneConstants.State getState() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public IccFileHandler getIccFileHandler(){
-        throw new RuntimeException("not implemented");
-    }
-
-    public Handler getHandler() {
-        return this;
-    }
-
-    public void updatePhoneObject(int voiceRadioTech) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public ServiceStateTracker getServiceStateTracker() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public CallTracker getCallTracker() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public AppType getCurrentUiccAppType() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public IccCard getIccCard() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getIccSerialNumber() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean getIccRecordsLoaded() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public List<CellInfo> getAllCellInfo() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setCellInfoListRate(int rateInMillis) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean getMessageWaitingIndicator() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setVoiceCallForwardingFlag(int line, boolean enable, String number) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean getCallForwardingIndicator() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void queryCdmaRoamingPreference(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public SignalStrength getSignalStrength() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setCdmaSubscription(int cdmaSubscriptionType, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setPreferredNetworkType(int networkType, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getPreferredNetworkType(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getSmscAddress(Message result) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setSmscAddress(String address, Message result) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setTTYMode(int ttyMode, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setUiTTYMode(int uiTtyMode, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void queryTTYMode(Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getEnhancedVoicePrivacy(Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setBandMode(int bandMode, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void queryAvailableBandMode(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void invokeOemRilRequestRaw(byte[] data, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void invokeOemRilRequestStrings(String[] strings, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void nvReadItem(int itemID, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void nvWriteItem(int itemID, String itemValue, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void nvWriteCdmaPrl(byte[] preferredRoamingList, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void nvResetConfig(int resetType, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyDataActivity() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyMessageWaitingIndicator() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyDataConnection(String reason, String apnType,
-            PhoneConstants.DataState state) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyDataConnection(String reason, String apnType) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyDataConnection(String reason) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyOtaspChanged(int otaspMode) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifySignalStrength() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyCellInfo(List<CellInfo> cellInfo) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
-        throw new RuntimeException("not implemented");
-    }
-
-    private final AtomicBoolean mInEmergencyCall = new AtomicBoolean(false);
-
-    public boolean isInEmergencyCall() {
-        return mInEmergencyCall.get();
-    }
-
-    @VisibleForTesting
-    public void setInEmergencyCall(boolean value) {
-        final boolean oldValue = mInEmergencyCall.getAndSet(value);
-        if (oldValue != value) {
-            mEmergencyCallToggledRegistrants.notifyRegistrants();
-        }
-    }
-
-    private final AtomicBoolean mInEcm = new AtomicBoolean(false);
-
-    public boolean isInEcm() {
-        return mInEcm.get();
-    }
-
-    @VisibleForTesting
-    public void setInEcm(boolean value) {
-        final boolean oldValue = mInEcm.getAndSet(value);
-        if (oldValue != value) {
-            mEmergencyCallToggledRegistrants.notifyRegistrants();
-        }
-    }
-
-    public boolean isVideoCallPresent() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getPhoneType() {
-        return PhoneConstants.PHONE_TYPE_GSM;
-    }
-
-    public int getPrecisePhoneType() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getVoiceMessageCount(){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setVoiceMessageCount(int countWaiting) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getCdmaEriIconIndex() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getCdmaEriIconMode() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getCdmaEriText() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getCdmaMin() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isMinInfoReady() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getCdmaPrlVersion(){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void exitEmergencyCallbackMode() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForCdmaOtaStatusChange(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForSubscriptionInfoReady(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean needsOtaServiceProvisioning() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public  boolean isOtaSpNumber(String dialStr) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForCallWaiting(Handler h, int what, Object obj){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForCallWaiting(Handler h){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForEcmTimerReset(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForEcmTimerReset(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForSignalInfo(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForSignalInfo(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForDisplayInfo(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForDisplayInfo(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForNumberInfo(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForNumberInfo(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForRedirectedNumberInfo(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForLineControlInfo(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForLineControlInfo(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerFoT53ClirlInfo(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForT53ClirInfo(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForT53AudioControlInfo(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForT53AudioControlInfo(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unsetOnEcbModeExitResponse(Handler h){
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForRadioOffOrNotAvailable(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForRadioOffOrNotAvailable(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String[] getActiveApnTypes() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean hasMatchedTetherApnSetting() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getActiveApnHost(String apnType) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public LinkProperties getLinkProperties(String apnType) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public NetworkCapabilities getNetworkCapabilities(String apnType) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isDataAllowed() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyNewRingingConnectionP(Connection cn) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyUnknownConnectionP(Connection cn) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyForVideoCapabilityChanged(boolean isVideoCallCapable) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isCspPlmnEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public IsimRecords getIsimRecords() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getMsisdn() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public PhoneConstants.DataState getDataConnectionState() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyCallForwardingIndicator() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyDataConnectionFailed(String reason, String apnType) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
-            String failCause) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getLteOnCdmaMode() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setVoiceMessageWaiting(int line, int countWaiting) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public UsimServiceTable getUsimServiceTable() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public UiccCard getUiccCard() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String[] getPcscfAddress(String apnType) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setImsRegistrationState(boolean registered) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public Phone getImsPhone() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isUtEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void dispose() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getSubId() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getPhoneId() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getVoicePhoneServiceState() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean setOperatorBrandOverride(String brand) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean setRoamingOverride(List<String> gsmRoamingList,
-            List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
-            List<String> cdmaNonRoamingList) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isMccMncMarkedAsRoaming(String mccMnc) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isMccMncMarkedAsNonRoaming(String mccMnc) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isSidMarkedAsRoaming(int SID) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isSidMarkedAsNonRoaming(int SID) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isImsRegistered() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isWifiCallingEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isVolteEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isRadioAvailable() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isRadioOn() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void shutdownRadio() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isShuttingDown() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setRadioCapability(RadioCapability rc, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getRadioAccessFamily() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getModemUuId() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public RadioCapability getRadioCapability() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void radioCapabilityUpdated(RadioCapability rc) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void sendSubscriptionSettings(boolean restoreNetworkSelection) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForRadioCapabilityChanged(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForRadioCapabilityChanged(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isImsUseEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isVideoEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public int getLceStatus() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getModemActivityInfo(Message response)  {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setAllowedCarriers(List<CarrierIdentifier> carrierList, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getAllowedCarriers(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void startLceAfterRadioIsAvailable() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public Locale getLocaleFromSimAndCarrierPrefs() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void updateDataConnectionTracker() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean updateCurrentCarrierInProvider() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForAllDataDisconnected(Handler h, int what) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForAllDataDisconnected(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public IccSmsInterfaceManager getIccSmsInterfaceManager(){
-        throw new RuntimeException("not implemented");
-    }
-
-    public static void checkWfcWifiOnlyModeBeforeDial(Phone imsPhone, Context context) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void startRingbackTone() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void stopRingbackTone() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void callEndCleanupHandOverCallIfAny() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void cancelUSSD(Message msg) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setBroadcastEmergencyCallStateChanges(boolean broadcast) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void sendEmergencyCallStateChange(boolean callActive) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public Phone getDefaultPhone() {
-        throw new RuntimeException("not implemented");
-    }
-
-    /** From PhoneInternalInterface - man this class has alot of functions */
-    public ServiceState getServiceState() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public CellLocation getCellLocation(WorkSource workSource) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public DataActivityState getDataActivityState() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public List<? extends MmiCode> getPendingMmiCodes() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void sendUssdResponse(String ussdMessge) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void registerForSuppServiceNotification(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void unregisterForSuppServiceNotification(Handler h) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void acceptCall(int videoState) throws CallStateException {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void rejectCall() throws CallStateException {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void switchHoldingAndActive() throws CallStateException {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean canConference() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void conference() throws CallStateException {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean canTransfer() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void explicitCallTransfer() throws CallStateException {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void clearDisconnected() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public Call getForegroundCall() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public Call getBackgroundCall() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public Call getRingingCall() {
-        throw new RuntimeException("not implemented");
-    }
-
-    @Override
-    public Connection dial(String dialString, DialArgs dialArgs) throws CallStateException {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean handlePinMmi(String dialString) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean handleUssdServiceCall(String dialString, Callback wrappedCallback) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean handleInCallMmiCommands(String command) throws CallStateException {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void sendDtmf(char c) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void startDtmf(char c) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void stopDtmf() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setRadioPower(boolean power) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getLine1Number() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getLine1AlphaTag() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean setLine1Number(String alphaTag, String number, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getVoiceMailNumber() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getVoiceMailAlphaTag() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setCallForwardingOption(int commandInterfaceCFReason, int commandInterfaceCFAction,
-            String dialingNumber, int timerSeconds, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getCallBarring(String facility, String password, Message onComplete,
-            int serviceClass) {
-    }
-
-    public void setCallBarring(String facility, boolean lockState, String password,
-            Message onComplete, int serviceClass) {
-    }
-
-    public void getOutgoingCallerIdDisplay(Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getCallWaiting(Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setCallWaiting(boolean enable, Message onComplete) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getAvailableNetworks(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void startNetworkScan(NetworkScanRequest nsr, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void stopNetworkScan(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setOnPostDialCharacter(Handler h, int what, Object obj) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setMute(boolean muted) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean getMute() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getDataCallList(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void updateServiceLocation() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void enableLocationUpdates() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void disableLocationUpdates() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean getDataRoamingEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setDataRoamingEnabled(boolean enable) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isUserDataEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getDeviceId() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getDeviceSvn() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getSubscriberId() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getGroupIdLevel1() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getGroupIdLevel2() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getEsn() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getMeid() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public String getImei() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void activateCellBroadcastSms(int activate, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void getCellBroadcastSmsConfig(Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        throw new RuntimeException("not implemented");
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneSwitcherMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneSwitcherMock.java
deleted file mode 100644
index b53a28f..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneSwitcherMock.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2006 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.mocks;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Registrant;
-import android.os.RegistrantList;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.PhoneSwitcher;
-import com.android.internal.telephony.SubscriptionController;
-
-import java.lang.reflect.Field;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class PhoneSwitcherMock extends PhoneSwitcher {
-    private final RegistrantList mActivePhoneRegistrants;
-    private final AtomicBoolean mIsActive[];
-
-    public PhoneSwitcherMock(int numPhones, Looper looper, SubscriptionController subController)
-            throws Exception {
-        super(numPhones, looper);
-
-        mActivePhoneRegistrants = new RegistrantList();
-        mIsActive = new AtomicBoolean[numPhones];
-        for(int i = 0; i < numPhones; i++) {
-            mIsActive[i] = new AtomicBoolean(false);
-        }
-
-        if (subController != null) {
-            Field subControllerField =
-                this.getClass().getSuperclass().getDeclaredField("mSubscriptionController");
-            subControllerField.setAccessible(true);
-            subControllerField.set(this, subController);
-        }
-    }
-
-    @Override
-    public void onRadioCapChanged(int phoneId) {
-        throw new RuntimeException("resendPhone not implemented");
-    }
-
-    @Override
-    protected boolean isPhoneActive(int phoneId) {
-        return mIsActive[phoneId].get();
-    }
-
-    @Override
-    public void registerForActivePhoneSwitch(Handler h, int what, Object o) {
-        Registrant r = new Registrant(h, what, o);
-        mActivePhoneRegistrants.add(r);
-        r.notifyRegistrant();
-    }
-
-    @Override
-    public void unregisterForActivePhoneSwitch(Handler h) {
-        mActivePhoneRegistrants.remove(h);
-    }
-
-    @VisibleForTesting
-    public void setPhoneActive(int phoneId, boolean active) {
-        validatePhoneId(phoneId);
-        if (mIsActive[phoneId].getAndSet(active) != active) {
-            notifyActivePhoneChange(phoneId);
-        }
-    }
-
-    public void setPreferredDataPhoneId(int preferredDataPhoneId) {
-        mPreferredDataPhoneId = preferredDataPhoneId;
-    }
-
-    public void notifyActivePhoneChange(int phoneId) {
-        mActivePhoneRegistrants.notifyRegistrants();
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
deleted file mode 100644
index 03ef19d..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2006 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.mocks;
-
-import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
-import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.telephony.SubscriptionInfo;
-
-import com.android.internal.telephony.ITelephonyRegistry;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.SubscriptionController;
-import com.android.internal.telephony.TelephonyIntents;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-// must extend SubscriptionController as some people use it directly within-process
-public class SubscriptionControllerMock extends SubscriptionController {
-    final AtomicInteger mDefaultDataSubId = new AtomicInteger(INVALID_SUBSCRIPTION_ID);
-    final AtomicInteger mDefaultVoiceSubId = new AtomicInteger(INVALID_SUBSCRIPTION_ID);
-    final ITelephonyRegistry.Stub mTelephonyRegistry;
-    final int[][] mSlotIndexToSubId;
-
-    public static SubscriptionController init(Context c) {
-        throw new RuntimeException("not implemented");
-    }
-    public static SubscriptionController getInstance() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public SubscriptionControllerMock(Context c, ITelephonyRegistry.Stub tr, int phoneCount) {
-        super(c);
-        mTelephonyRegistry = tr;
-        mSlotIndexToSubId = new int[phoneCount][];
-        for (int i = 0; i < phoneCount; i++) {
-            mSlotIndexToSubId[i] = new int[1];
-            mSlotIndexToSubId[i][0] = INVALID_SUBSCRIPTION_ID;
-        }
-    }
-
-    protected void internalInit(Context c) {
-        mContext = c;
-    }
-
-    @Override
-    public int getDefaultDataSubId() {
-        return mDefaultDataSubId.get();
-    }
-
-    @Override
-    public void setDefaultDataSubId(int subId) {
-        if (subId == DEFAULT_SUBSCRIPTION_ID) {
-            throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUB_ID");
-        }
-
-        mDefaultDataSubId.set(subId);
-        broadcastDefaultDataSubIdChanged(subId);
-    }
-
-    private void broadcastDefaultDataSubIdChanged(int subId) {
-        // Broadcast an Intent for default data sub change
-        Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
-        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    @Override
-    public int getSubIdUsingPhoneId(int phoneId) {
-        int[] subIds = getSubId(phoneId);
-        if (subIds == null || subIds.length == 0) {
-            return INVALID_SUBSCRIPTION_ID;
-        }
-        return subIds[0];
-    }
-
-    @Override
-    public void notifySubscriptionInfoChanged() {
-        try {
-            mTelephonyRegistry.notifySubscriptionInfoChanged();
-        } catch (RemoteException ex) {}
-    }
-    @Override
-    public SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId, String callingPackage) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, String cp){
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public List<SubscriptionInfo> getAllSubInfoList(String callingPackage) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int getActiveSubInfoCount(String callingPackage) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int getAllSubInfoCount(String callingPackage) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int getActiveSubInfoCountMax() {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int addSubInfoRecord(String iccId, int slotIndex) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int addSubInfo(String uniqueId, String displayName, int slotIndex,
-            int subscriptionType) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int removeSubInfo(String uniqueId, int subscriptionType) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public boolean setPlmnSpn(int slotIndex, boolean showPlmn, String plmn, boolean showSpn,
-            String spn) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int setIconTint(int tint, int subId) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int setDisplayNameUsingSrc(String displayName, int subId, int nameSource) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int setDisplayNumber(String number, int subId) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int setDataRoaming(int roaming, int subId) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int setMccMnc(String mccMnc, int subId) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int getSlotIndex(int subId) {
-        throw new RuntimeException("not implemented");
-    }
-
-    private boolean isInvalidslotIndex(int slotIndex) {
-        if (slotIndex < 0 || slotIndex >= mSlotIndexToSubId.length) return true;
-        return false;
-    }
-
-    @Override
-    public int[] getSubId(int slotIndex) {
-        if (isInvalidslotIndex(slotIndex)) {
-            return null;
-        }
-        return mSlotIndexToSubId[slotIndex];
-    }
-    public void setSlotSubId(int slotIndex, int subId) {
-        if (isInvalidslotIndex(slotIndex)) {
-            throw new RuntimeException("invalid slot specified" + slotIndex);
-        }
-        if (mSlotIndexToSubId[slotIndex][0] != subId) {
-            mSlotIndexToSubId[slotIndex][0] = subId;
-            try {
-                mTelephonyRegistry.notifySubscriptionInfoChanged();
-            } catch (RemoteException ex) {}
-        }
-    }
-    @Override
-    public int getPhoneId(int subId) {
-        if (subId <= INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX;
-
-        for (int i = 0; i < mSlotIndexToSubId.length; i++) {
-            if (mSlotIndexToSubId[i][0] == subId) return i;
-        }
-        return INVALID_PHONE_INDEX;
-    }
-    @Override
-    public int clearSubInfo() {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int getDefaultSubId() {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public void setDefaultSmsSubId(int subId) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int getDefaultSmsSubId() {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public void setDefaultVoiceSubId(int subId) {
-        if (subId == DEFAULT_SUBSCRIPTION_ID) {
-            throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUB_ID");
-        }
-        mDefaultVoiceSubId.set(subId);
-        broadcastDefaultVoiceSubIdChanged(subId);
-    }
-    @Override
-    public int getDefaultVoiceSubId() {
-        if (mDefaultVoiceSubId != null) {
-            return mDefaultVoiceSubId.get();
-        } else {
-            return INVALID_SUBSCRIPTION_ID;
-        }
-    }
-    @Override
-    public void updatePhonesAvailability(Phone[] phones) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int[] getActiveSubIdList(boolean visibleOnly) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public boolean isActiveSubId(int subId) {
-        return getPhoneId(subId) != INVALID_PHONE_INDEX;
-    }
-    @Override
-    public int getSimStateForSlotIndex(int slotIndex) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public int setSubscriptionProperty(int subId, String propKey, String propValue) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public String getSubscriptionProperty(int subId, String propKey, String callingPackage) {
-        throw new RuntimeException("not implemented");
-    }
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        throw new RuntimeException("not implemented");
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionMonitorMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionMonitorMock.java
deleted file mode 100644
index 7579359..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionMonitorMock.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2006 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.mocks;
-
-import android.os.Handler;
-import android.os.Registrant;
-import android.os.RegistrantList;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.SubscriptionMonitor;
-
-public class SubscriptionMonitorMock extends SubscriptionMonitor {
-    private final int mNumPhones;
-    private final RegistrantList mSubscriptionsChangedRegistrants[];
-
-    public SubscriptionMonitorMock(int numPhones) {
-        super();
-        mNumPhones = numPhones;
-        mSubscriptionsChangedRegistrants = new RegistrantList[numPhones];
-
-        for (int i = 0; i < numPhones; i++) {
-            mSubscriptionsChangedRegistrants[i] = new RegistrantList();
-        }
-    }
-
-    @Override
-    public void registerForSubscriptionChanged(int phoneId, Handler h, int what, Object o) {
-        validatePhoneId(phoneId);
-        Registrant r = new Registrant(h, what, o);
-        mSubscriptionsChangedRegistrants[phoneId].add(r);
-        r.notifyRegistrant();
-    }
-
-    @Override
-    public void unregisterForSubscriptionChanged(int phoneId, Handler h) {
-        validatePhoneId(phoneId);
-        mSubscriptionsChangedRegistrants[phoneId].remove(h);
-    }
-
-    @VisibleForTesting
-    public void notifySubscriptionChanged(int phoneId) {
-        validatePhoneId(phoneId);
-        mSubscriptionsChangedRegistrants[phoneId].notifyRegistrants();
-    }
-
-    private void validatePhoneId(int phoneId) {
-        if (phoneId < 0 || phoneId >= mNumPhones) {
-            throw new IllegalArgumentException("Invalid PhoneId");
-        }
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
deleted file mode 100644
index bc2cf62..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Copyright (C) 2006 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.mocks;
-
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.telephony.Annotation.DataFailureCause;
-import android.telephony.CallQuality;
-import android.telephony.CellInfo;
-import android.telephony.DataFailCause;
-import android.telephony.PhoneCapability;
-import android.telephony.PhysicalChannelConfig;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.SubscriptionManager;
-import android.telephony.emergency.EmergencyNumber;
-import android.telephony.ims.ImsReasonInfo;
-
-import com.android.internal.telephony.IOnSubscriptionsChangedListener;
-import com.android.internal.telephony.IPhoneStateListener;
-import com.android.internal.telephony.ITelephonyRegistry;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class TelephonyRegistryMock extends ITelephonyRegistry.Stub {
-
-    private static class Record {
-        String callingPackage;
-
-        IBinder binder;
-
-        IPhoneStateListener callback;
-        IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
-        IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback;
-
-        int callerUserId;
-
-        int events;
-
-        int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-        int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
-
-        boolean canReadPhoneState;
-
-        boolean matchPhoneStateListenerEvent(int events) {
-            return (callback != null) && ((events & this.events) != 0);
-        }
-
-        boolean matchOnSubscriptionsChangedListener() {
-            return (onSubscriptionsChangedListenerCallback != null);
-        }
-
-        boolean matchOnOpportunisticSubscriptionsChangedListener() {
-            return (onOpportunisticSubscriptionsChangedListenerCallback != null);
-        }
-
-
-        @Override
-        public String toString() {
-            return "{callingPackage=" + callingPackage + " binder=" + binder
-                    + " callback=" + callback
-                    + " onSubscriptionsChangedListenerCallback="
-                    + onSubscriptionsChangedListenerCallback
-                    + " onOpportunisticSubscriptionsChangedListenerCallback="
-                    + onOpportunisticSubscriptionsChangedListenerCallback
-                    + " callerUserId=" + callerUserId + " subId=" + subId + " phoneId=" + phoneId
-                    + " events=" + Integer.toHexString(events)
-                    + " canReadPhoneState=" + canReadPhoneState + "}";
-        }
-    }
-
-    private final ArrayList<IBinder> mRemoveList = new ArrayList<IBinder>();
-    private final ArrayList<Record> mRecords = new ArrayList<Record>();
-    private boolean mHasNotifySubscriptionInfoChangedOccurred = false;
-    private boolean mHasNotifyOpportunisticSubscriptionInfoChangedOccurred = false;
-
-    public TelephonyRegistryMock() {
-    }
-
-    private void remove(IBinder binder) {
-        synchronized (mRecords) {
-            final int recordCount = mRecords.size();
-            for (int i = 0; i < recordCount; i++) {
-                if (mRecords.get(i).binder == binder) {
-                    mRecords.remove(i);
-                    return;
-                }
-            }
-        }
-    }
-
-    private void handleRemoveListLocked() {
-        int size = mRemoveList.size();
-        if (size > 0) {
-            for (IBinder b: mRemoveList) {
-                remove(b);
-            }
-            mRemoveList.clear();
-        }
-    }
-
-
-    @Override
-    public void addOnSubscriptionsChangedListener(String callingPackage,
-            IOnSubscriptionsChangedListener callback) {
-        Record r;
-
-        synchronized (mRecords) {
-            // register
-            find_and_add: {
-                IBinder b = callback.asBinder();
-                final int N = mRecords.size();
-                for (int i = 0; i < N; i++) {
-                    r = mRecords.get(i);
-                    if (b == r.binder) {
-                        break find_and_add;
-                    }
-                }
-                r = new Record();
-                r.binder = b;
-                mRecords.add(r);
-            }
-
-            r.onSubscriptionsChangedListenerCallback = callback;
-            r.callingPackage = callingPackage;
-            r.callerUserId = UserHandle.getCallingUserId();
-            r.events = 0;
-            r.canReadPhoneState = true; // permission has been enforced above
-            // Always notify when registration occurs if there has been a notification.
-            if (mHasNotifySubscriptionInfoChangedOccurred) {
-                try {
-                    r.onSubscriptionsChangedListenerCallback.onSubscriptionsChanged();
-                } catch (RemoteException e) {
-                    remove(r.binder);
-                }
-            } else {
-                //log("listen oscl: mHasNotifySubscriptionInfoChangedOccurred==false no callback");
-            }
-        }
-
-    }
-
-    @Override
-    public void addOnOpportunisticSubscriptionsChangedListener(String callingPackage,
-            IOnSubscriptionsChangedListener callback) {
-        Record r;
-
-        synchronized (mRecords) {
-            // register
-            find_and_add: {
-                IBinder b = callback.asBinder();
-                final int n = mRecords.size();
-                for (int i = 0; i < n; i++) {
-                    r = mRecords.get(i);
-                    if (b == r.binder) {
-                        break find_and_add;
-                    }
-                }
-                r = new Record();
-                r.binder = b;
-                mRecords.add(r);
-            }
-
-            r.onOpportunisticSubscriptionsChangedListenerCallback = callback;
-            r.callingPackage = callingPackage;
-            r.callerUserId = UserHandle.getUserHandleForUid(Binder.getCallingUid()).getIdentifier();
-            r.events = 0;
-            r.canReadPhoneState = true; // permission has been enforced above
-            // Always notify when registration occurs if there has been a notification.
-            if (mHasNotifyOpportunisticSubscriptionInfoChangedOccurred) {
-                try {
-                    r.onOpportunisticSubscriptionsChangedListenerCallback.onSubscriptionsChanged();
-                } catch (RemoteException e) {
-                    remove(r.binder);
-                }
-            } else {
-                //log("listen oscl: mHasNotifySubscriptionInfoChangedOccurred==false no callback");
-            }
-        }
-
-    }
-
-    @Override
-    public void removeOnSubscriptionsChangedListener(String pkgForDebug,
-            IOnSubscriptionsChangedListener callback) {
-        remove(callback.asBinder());
-    }
-
-    @Override
-    public void notifySubscriptionInfoChanged() {
-        synchronized (mRecords) {
-            if (!mHasNotifySubscriptionInfoChangedOccurred) {
-                //log("notifySubscriptionInfoChanged: first invocation mRecords.size="
-                //        + mRecords.size());
-            }
-            mHasNotifySubscriptionInfoChangedOccurred = true;
-            mRemoveList.clear();
-            for (Record r : mRecords) {
-                if (r.matchOnSubscriptionsChangedListener()) {
-                    try {
-                        r.onSubscriptionsChangedListenerCallback.onSubscriptionsChanged();
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
-    @Override
-    public void notifyOpportunisticSubscriptionInfoChanged() {
-        synchronized (mRecords) {
-            if (!mHasNotifyOpportunisticSubscriptionInfoChangedOccurred) {
-                //log("notifySubscriptionInfoChanged: first invocation mRecords.size="
-                //        + mRecords.size());
-            }
-            mHasNotifyOpportunisticSubscriptionInfoChangedOccurred = true;
-            mRemoveList.clear();
-            for (Record r : mRecords) {
-                if (r.matchOnOpportunisticSubscriptionsChangedListener()) {
-                    try {
-                        r.onOpportunisticSubscriptionsChangedListenerCallback
-                                .onSubscriptionsChanged();
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
-    @Override
-    public void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void listenForSubscriber(int subId, String pkg, IPhoneStateListener callback, int events,
-                                    boolean notifyNow) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCallStateForAllSubs(int state, String incomingNumber) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCallState(int phoneId, int subId, int state,
-                String incomingNumber) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyServiceStateForPhoneId(int phoneId, int subId, ServiceState state) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifySignalStrengthForPhoneId(int phoneId, int subId,
-                SignalStrength signalStrength) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCallForwardingChanged(boolean cfi) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCallForwardingChangedForSubscriber(int subId, boolean cfi) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyDataActivity(int state) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyDataActivityForSubscriber(int subId, int state) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
-            String apn, String apnType, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyDataConnectionForSubscriber(int phoneId, int subId, int state,
-            boolean isDataConnectivityPossible, String apn, String apnType,
-            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
-            int networkType, boolean roaming) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyDataConnectionFailed(String apnType) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyDataConnectionFailedForSubscriber(int phoneId, int subId, String apnType) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCellLocation(Bundle cellLocation) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyOtaspChanged(int subId, int otaspMode) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCellInfo(List<CellInfo> cellInfo) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyPhysicalChannelConfigurationForSubscriber(int phoneId, int subId,
-            List<PhysicalChannelConfig> configs) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyEmergencyNumberList(int phoneId, int subId) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyOutgoingEmergencyCall(int phoneId, int subId,
-            EmergencyNumber emergencyNumber) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyOutgoingEmergencySms(int phoneId, int subId,
-            EmergencyNumber emergencyNumber) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCallQualityChanged(CallQuality callQuality, int phoneId, int subId,
-            int callNetworkType) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
-                                       int foregroundCallState, int backgroundCallState) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
-                                      int preciseDisconnectCause) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyPreciseDataConnectionFailed(int phoneId, int subId,
-                                                  String apnType, String apn,
-                                                  @DataFailureCause int failCause) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCellInfoForSubscriber(int subId, List<CellInfo> cellInfo) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifySrvccStateChanged(int subId, int state) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyOemHookRawEventForSubscriber(int phoneId, int subId, byte[] rawData) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyCarrierNetworkChange(boolean active) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifySimActivationStateChangedForPhoneId(int phoneId, int subId,
-                                                          int activationType, int state) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyUserMobileDataStateChangedForPhoneId(int phoneId, int subId, boolean state) {
-    }
-
-    @Override
-    public void notifyPhoneCapabilityChanged(PhoneCapability capability) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyActiveDataSubIdChanged(int subId) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyRadioPowerStateChanged(int phoneId, int subId, int state) {
-        throw new RuntimeException("Not implemented");
-    }
-
-    @Override
-    public void notifyImsDisconnectCause(int subId, ImsReasonInfo imsReasonInfo)  {
-        throw new RuntimeException("Not implemented");
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java
index 01efb40..8c4eab1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/nitz/NewNitzStateMachineImplTest.java
@@ -16,9 +16,14 @@
 
 package com.android.internal.telephony.nitz;
 
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+
 import static com.android.internal.telephony.NitzStateMachineTestSupport.ARBITRARY_SYSTEM_CLOCK_TIME;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.UNIQUE_US_ZONE_SCENARIO1;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.UNITED_KINGDOM_SCENARIO;
+import static com.android.internal.telephony.NitzStateMachineTestSupport.createEmptyTimeSuggestion;
+import static com.android.internal.telephony.NitzStateMachineTestSupport.createEmptyTimeZoneSuggestion;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.createTimeSuggestionFromNitzSignal;
 
 import static org.junit.Assert.assertEquals;
@@ -28,17 +33,17 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import android.app.timedetector.PhoneTimeSuggestion;
-import android.util.TimestampedValue;
+import android.app.timedetector.TelephonyTimeSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.os.TimestampedValue;
 
+import com.android.internal.telephony.IndentingPrintWriter;
 import com.android.internal.telephony.NitzData;
 import com.android.internal.telephony.NitzStateMachineTestSupport.FakeDeviceState;
 import com.android.internal.telephony.NitzStateMachineTestSupport.Scenario;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.TimeZoneLookupHelper;
 import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.NitzSignalInputFilterPredicate;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
-import com.android.internal.util.IndentingPrintWriter;
 
 import org.junit.After;
 import org.junit.Before;
@@ -50,9 +55,11 @@
 
 public class NewNitzStateMachineImplTest extends TelephonyTest {
 
-    private static final int PHONE_ID = 99999;
-    private static final PhoneTimeZoneSuggestion EMPTY_TIME_ZONE_SUGGESTION =
-            new PhoneTimeZoneSuggestion(PHONE_ID);
+    private static final int SLOT_INDEX = 99999;
+    private static final TelephonyTimeZoneSuggestion EMPTY_TIME_ZONE_SUGGESTION =
+            createEmptyTimeZoneSuggestion(SLOT_INDEX);
+    private static final TelephonyTimeSuggestion EMPTY_TIME_SUGGESTION =
+            createEmptyTimeSuggestion(SLOT_INDEX);
 
     private FakeNewTimeServiceHelper mFakeNewTimeServiceHelper;
     private FakeDeviceState mFakeDeviceState;
@@ -84,7 +91,7 @@
         mRealTimeZoneSuggester = new TimeZoneSuggesterImpl(mFakeDeviceState, timeZoneLookupHelper);
 
         mNitzStateMachineImpl = new NewNitzStateMachineImpl(
-                PHONE_ID, mFakeNitzSignalInputFilter, mRealTimeZoneSuggester,
+                SLOT_INDEX, mFakeNitzSignalInputFilter, mRealTimeZoneSuggester,
                 mFakeNewTimeServiceHelper);
 
         TelephonyTest.logd("NewNitzStateMachineImplTest -Setup!");
@@ -104,12 +111,12 @@
 
         // Capture expected results from the real suggester and confirm we can tell the difference
         // between them.
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion1 =
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion1 =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, networkCountryIsoCode, null /* nitzSignal */);
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion2 =
+                        SLOT_INDEX, networkCountryIsoCode, null /* nitzSignal */);
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion2 =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, networkCountryIsoCode, nitzSignal);
+                        SLOT_INDEX, networkCountryIsoCode, nitzSignal);
         assertNotNull(expectedTimeZoneSuggestion2);
         assertNotEquals(expectedTimeZoneSuggestion1, expectedTimeZoneSuggestion2);
 
@@ -128,8 +135,8 @@
         // Simulate NITZ being received and verify the behavior.
         script.nitzReceived(nitzSignal);
 
-        PhoneTimeSuggestion expectedTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, nitzSignal);
+        TelephonyTimeSuggestion expectedTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, nitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedTimeSuggestion, expectedTimeZoneSuggestion2);
 
@@ -147,12 +154,12 @@
 
         // Capture test expectations from the real suggester and confirm we can tell the difference
         // between them.
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion1 =
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion1 =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, null /* countryIsoCode */, nitzSignal);
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion2 =
+                        SLOT_INDEX, null /* countryIsoCode */, nitzSignal);
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion2 =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, networkCountryIsoCode, nitzSignal);
+                        SLOT_INDEX, networkCountryIsoCode, nitzSignal);
         assertNotEquals(expectedTimeZoneSuggestion1, expectedTimeZoneSuggestion2);
 
         Script script = new Script()
@@ -163,8 +170,8 @@
         script.nitzReceived(nitzSignal);
 
         // Verify the state machine did the right thing.
-        PhoneTimeSuggestion expectedTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, nitzSignal);
+        TelephonyTimeSuggestion expectedTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, nitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedTimeSuggestion, expectedTimeZoneSuggestion1);
 
@@ -201,16 +208,16 @@
         // Simulate receiving the NITZ signal.
         script.nitzReceived(nitzSignal);
 
-        PhoneTimeSuggestion expectedTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, nitzSignal);
+        TelephonyTimeSuggestion expectedTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, nitzSignal);
         // Capture output from the real suggester and confirm it meets the test's needs /
         // expectations.
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, "" /* countryIsoCode */, nitzSignal);
-        assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
+                        SLOT_INDEX, "" /* countryIsoCode */, nitzSignal);
+        assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY,
                 expectedTimeZoneSuggestion.getMatchType());
-        assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
+        assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
                 expectedTimeZoneSuggestion.getQuality());
 
         // Verify the state machine did the right thing.
@@ -236,8 +243,8 @@
 
         // Verify the state machine did the right thing.
         // No time zone should be set. A NITZ signal by itself is not enough.
-        PhoneTimeSuggestion expectedTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, nitzSignal);
+        TelephonyTimeSuggestion expectedTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, nitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedTimeSuggestion, EMPTY_TIME_ZONE_SUGGESTION);
 
@@ -249,12 +256,12 @@
 
         // Capture output from the real suggester and confirm it meets the test's needs /
         // expectations.
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, "" /* countryIsoCode */, nitzSignal);
-        assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
+                        SLOT_INDEX, "" /* countryIsoCode */, nitzSignal);
+        assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY,
                 expectedTimeZoneSuggestion.getMatchType());
-        assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
+        assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
                 expectedTimeZoneSuggestion.getQuality());
 
         // Verify the state machine did the right thing.
@@ -277,8 +284,8 @@
         // zone.
         TimestampedValue<NitzData> preFlightNitzSignal =
                 scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-        PhoneTimeSuggestion expectedPreFlightTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, preFlightNitzSignal);
+        TelephonyTimeSuggestion expectedPreFlightTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, preFlightNitzSignal);
         String preFlightCountryIsoCode = scenario.getNetworkCountryIsoCode();
 
         // Simulate receiving the NITZ signal and country.
@@ -286,9 +293,9 @@
                 .countryReceived(preFlightCountryIsoCode);
 
         // Verify the state machine did the right thing.
-        PhoneTimeZoneSuggestion expectedPreFlightTimeZoneSuggestion =
+        TelephonyTimeZoneSuggestion expectedPreFlightTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, preFlightCountryIsoCode, preFlightNitzSignal);
+                        SLOT_INDEX, preFlightCountryIsoCode, preFlightNitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedPreFlightTimeSuggestion, expectedPreFlightTimeZoneSuggestion);
 
@@ -307,7 +314,8 @@
 
         // Verify the state machine did the right thing.
         // Check the time zone suggestion was withdrawn (time is not currently withdrawn).
-        script.verifyOnlyTimeZoneWasSuggestedAndReset(EMPTY_TIME_ZONE_SUGGESTION);
+        script.verifyTimeAndTimeZoneSuggestedAndReset(
+                EMPTY_TIME_SUGGESTION, EMPTY_TIME_ZONE_SUGGESTION);
 
         // Check state that NitzStateMachine must expose.
         assertNull(mNitzStateMachineImpl.getCachedNitzData());
@@ -322,8 +330,8 @@
         // Simulate airplane mode being turned off.
         script.toggleAirplaneMode(false);
 
-        // Verify the time zone suggestion was withdrawn.
-        script.verifyOnlyTimeZoneWasSuggestedAndReset(EMPTY_TIME_ZONE_SUGGESTION);
+        // Verify nothing was suggested: The last suggestion was empty so nothing has changed.
+        script.verifyNothingWasSuggested();
 
         // Check the state that NitzStateMachine must expose.
         assertNull(mNitzStateMachineImpl.getCachedNitzData());
@@ -347,11 +355,11 @@
                 .nitzReceived(postFlightNitzSignal);
 
         // Verify the state machine did the right thing.
-        PhoneTimeSuggestion expectedPostFlightTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, postFlightNitzSignal);
-        PhoneTimeZoneSuggestion expectedPostFlightTimeZoneSuggestion =
+        TelephonyTimeSuggestion expectedPostFlightTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, postFlightNitzSignal);
+        TelephonyTimeZoneSuggestion expectedPostFlightTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, postFlightCountryCode, postFlightNitzSignal);
+                        SLOT_INDEX, postFlightCountryCode, postFlightNitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedPostFlightTimeSuggestion, expectedPostFlightTimeZoneSuggestion);
 
@@ -375,17 +383,17 @@
         // Simulate a device receiving signals that allow it to detect time and time zone.
         TimestampedValue<NitzData> initialNitzSignal =
                 scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-        PhoneTimeSuggestion expectedInitialTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, initialNitzSignal);
+        TelephonyTimeSuggestion expectedInitialTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, initialNitzSignal);
 
         // Simulate receiving the NITZ signal and country.
         script.nitzReceived(initialNitzSignal)
                 .countryReceived(countryIsoCode);
 
         // Verify the state machine did the right thing.
-        PhoneTimeZoneSuggestion expectedInitialTimeZoneSuggestion =
+        TelephonyTimeZoneSuggestion expectedInitialTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, countryIsoCode, initialNitzSignal);
+                        SLOT_INDEX, countryIsoCode, initialNitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedInitialTimeSuggestion, expectedInitialTimeZoneSuggestion);
 
@@ -399,12 +407,12 @@
         // Simulate network being lost.
         script.networkUnavailable();
 
-        // Verify the state machine did the right thing.
-        // Check the "no NITZ" time zone suggestion is made (time is not currently withdrawn).
-        PhoneTimeZoneSuggestion expectedMiddleTimeZoneSuggestion =
+        // Check the "no NITZ" time and time zone suggestions are made.
+        TelephonyTimeZoneSuggestion expectedMiddleTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, countryIsoCode, null /* nitzSignal */);
-        script.verifyOnlyTimeZoneWasSuggestedAndReset(expectedMiddleTimeZoneSuggestion);
+                        SLOT_INDEX, countryIsoCode, null /* nitzSignal */);
+        script.verifyTimeAndTimeZoneSuggestedAndReset(
+                EMPTY_TIME_SUGGESTION, expectedMiddleTimeZoneSuggestion);
 
         // Check state that NitzStateMachine must expose.
         assertNull(mNitzStateMachineImpl.getCachedNitzData());
@@ -431,11 +439,11 @@
         script.nitzReceived(finalNitzSignal);
 
         // Verify the state machine did the right thing.
-        PhoneTimeSuggestion expectedFinalTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, finalNitzSignal);
-        PhoneTimeZoneSuggestion expectedFinalTimeZoneSuggestion =
+        TelephonyTimeSuggestion expectedFinalTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, finalNitzSignal);
+        TelephonyTimeZoneSuggestion expectedFinalTimeZoneSuggestion =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, countryIsoCode, finalNitzSignal);
+                        SLOT_INDEX, countryIsoCode, finalNitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedFinalTimeSuggestion, expectedFinalTimeZoneSuggestion);
 
@@ -455,18 +463,18 @@
 
         // Simulate receiving the country and verify the state machine does the right thing.
         script.countryReceived(scenario.getNetworkCountryIsoCode());
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion1 =
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion1 =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+                        SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
         script.verifyOnlyTimeZoneWasSuggestedAndReset(expectedTimeZoneSuggestion1);
 
         // Simulate receiving an NITZ signal and verify the state machine does the right thing.
         script.nitzReceived(nitzSignal);
-        PhoneTimeSuggestion expectedTimeSuggestion =
-                createTimeSuggestionFromNitzSignal(PHONE_ID, nitzSignal);
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion2 =
+        TelephonyTimeSuggestion expectedTimeSuggestion =
+                createTimeSuggestionFromNitzSignal(SLOT_INDEX, nitzSignal);
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion2 =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
+                        SLOT_INDEX, scenario.getNetworkCountryIsoCode(), nitzSignal);
         script.verifyTimeAndTimeZoneSuggestedAndReset(
                 expectedTimeSuggestion, expectedTimeZoneSuggestion2);
 
@@ -476,9 +484,9 @@
         // Simulate the country becoming unavailable and verify the state machine does the right
         // thing.
         script.countryUnavailable();
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion3 =
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion3 =
                 mRealTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, null /* countryIsoCode */, nitzSignal);
+                        SLOT_INDEX, null /* countryIsoCode */, nitzSignal);
         script.verifyOnlyTimeZoneWasSuggestedAndReset(expectedTimeZoneSuggestion3);
 
         // Check state that NitzStateMachine must expose.
@@ -550,15 +558,16 @@
             return this;
         }
 
-        Script verifyOnlyTimeZoneWasSuggestedAndReset(PhoneTimeZoneSuggestion timeZoneSuggestion) {
+        Script verifyOnlyTimeZoneWasSuggestedAndReset(
+                TelephonyTimeZoneSuggestion timeZoneSuggestion) {
             justVerifyTimeZoneWasSuggested(timeZoneSuggestion);
             justVerifyTimeWasNotSuggested();
             commitStateChanges();
             return this;
         }
 
-        Script verifyTimeAndTimeZoneSuggestedAndReset(
-                PhoneTimeSuggestion timeSuggestion, PhoneTimeZoneSuggestion timeZoneSuggestion) {
+        Script verifyTimeAndTimeZoneSuggestedAndReset(TelephonyTimeSuggestion timeSuggestion,
+                TelephonyTimeZoneSuggestion timeZoneSuggestion) {
             justVerifyTimeZoneWasSuggested(timeZoneSuggestion);
             justVerifyTimeWasSuggested(timeSuggestion);
             commitStateChanges();
@@ -569,12 +578,13 @@
             mFakeNewTimeServiceHelper.suggestedTimes.assertHasNotBeenSet();
         }
 
-        private void justVerifyTimeZoneWasSuggested(PhoneTimeZoneSuggestion timeZoneSuggestion) {
+        private void justVerifyTimeZoneWasSuggested(
+                TelephonyTimeZoneSuggestion timeZoneSuggestion) {
             mFakeNewTimeServiceHelper.suggestedTimeZones.assertHasBeenSet();
             mFakeNewTimeServiceHelper.suggestedTimeZones.assertLatestEquals(timeZoneSuggestion);
         }
 
-        private void justVerifyTimeWasSuggested(PhoneTimeSuggestion timeSuggestion) {
+        private void justVerifyTimeWasSuggested(TelephonyTimeSuggestion timeSuggestion) {
             mFakeNewTimeServiceHelper.suggestedTimes.assertChangeCount(1);
             mFakeNewTimeServiceHelper.suggestedTimes.assertLatestEquals(timeSuggestion);
         }
@@ -642,22 +652,24 @@
         private final FakeDeviceState mFakeDeviceState;
 
         // State we want to track.
-        public final TestState<PhoneTimeSuggestion> suggestedTimes = new TestState<>();
-        public final TestState<PhoneTimeZoneSuggestion> suggestedTimeZones = new TestState<>();
+        public final TestState<TelephonyTimeSuggestion> suggestedTimes = new TestState<>();
+        public final TestState<TelephonyTimeZoneSuggestion> suggestedTimeZones = new TestState<>();
 
         FakeNewTimeServiceHelper(FakeDeviceState fakeDeviceState) {
             mFakeDeviceState = fakeDeviceState;
         }
 
         @Override
-        public void suggestDeviceTime(PhoneTimeSuggestion timeSuggestion) {
+        public void suggestDeviceTime(TelephonyTimeSuggestion timeSuggestion) {
             suggestedTimes.set(timeSuggestion);
-            // The fake time service just uses the latest suggestion.
-            mFakeDeviceState.currentTimeMillis = timeSuggestion.getUtcTime().getValue();
+            if (timeSuggestion.getUtcTime() != null) {
+                // The fake time service just uses the latest suggestion.
+                mFakeDeviceState.currentTimeMillis = timeSuggestion.getUtcTime().getValue();
+            }
         }
 
         @Override
-        public void maybeSuggestDeviceTimeZone(PhoneTimeZoneSuggestion timeZoneSuggestion) {
+        public void maybeSuggestDeviceTimeZone(TelephonyTimeZoneSuggestion timeZoneSuggestion) {
             suggestedTimeZones.set(timeZoneSuggestion);
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactoryTest.java
index 3e69d23..e1561f8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzSignalInputFilterPredicateFactoryTest.java
@@ -26,7 +26,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
 
 import com.android.internal.telephony.NitzData;
 import com.android.internal.telephony.NitzStateMachineTestSupport.FakeDeviceState;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java
index cdd30e4..c32e447 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/nitz/TimeZoneSuggesterImplTest.java
@@ -16,6 +16,14 @@
 
 package com.android.internal.telephony.nitz;
 
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+
 import static com.android.internal.telephony.NitzStateMachineTestSupport.ARBITRARY_REALTIME_MILLIS;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.CZECHIA_SCENARIO;
 import static com.android.internal.telephony.NitzStateMachineTestSupport.NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID;
@@ -31,7 +39,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.util.TimestampedValue;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.os.TimestampedValue;
 
 import com.android.internal.telephony.NitzData;
 import com.android.internal.telephony.NitzStateMachineTestSupport.FakeDeviceState;
@@ -39,7 +48,6 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.TimeZoneLookupHelper;
 import com.android.internal.telephony.nitz.NewNitzStateMachineImpl.TimeZoneSuggester;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion;
 
 import org.junit.After;
 import org.junit.Before;
@@ -50,9 +58,9 @@
 
 public class TimeZoneSuggesterImplTest extends TelephonyTest {
 
-    private static final int PHONE_ID = 99999;
-    private static final PhoneTimeZoneSuggestion EMPTY_TIME_ZONE_SUGGESTION =
-            new PhoneTimeZoneSuggestion(PHONE_ID);
+    private static final int SLOT_INDEX = 99999;
+    private static final TelephonyTimeZoneSuggestion EMPTY_TIME_ZONE_SUGGESTION =
+            new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX).build();
 
     private FakeDeviceState mFakeDeviceState;
     private TimeZoneSuggester mTimeZoneSuggester;
@@ -82,7 +90,7 @@
     public void test_emptySuggestionForNullCountryNullNitz() throws Exception {
         assertEquals(EMPTY_TIME_ZONE_SUGGESTION,
                 mTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, null /* countryIsoCode */, null /* nitzSignal */));
+                        SLOT_INDEX, null /* countryIsoCode */, null /* nitzSignal */));
     }
 
     @Test
@@ -92,14 +100,14 @@
                 scenario.createNitzSignal(ARBITRARY_REALTIME_MILLIS);
         assertEquals(EMPTY_TIME_ZONE_SUGGESTION,
                 mTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, null /* countryIsoCode */, nitzSignal));
+                        SLOT_INDEX, null /* countryIsoCode */, nitzSignal));
     }
 
     @Test
     public void test_emptySuggestionForEmptyCountryNullNitz() throws Exception {
         assertEquals(EMPTY_TIME_ZONE_SUGGESTION,
                 mTimeZoneSuggester.getTimeZoneSuggestion(
-                        PHONE_ID, "" /* countryIsoCoe */, null /* nitzSignal */));
+                        SLOT_INDEX, "" /* countryIsoCoe */, null /* nitzSignal */));
     }
 
     /**
@@ -115,51 +123,47 @@
         // Country won't be enough to get a quality result for time zone detection but a suggestion
         // will be made.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
 
         // NITZ with a "" country code is interpreted as a test network so only offset is used
         // to get a match.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, "" /* countryIsoCode */,
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, "" /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
-            assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(SLOT_INDEX, actualSuggestion.getSlotIndex());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
         }
 
         // NITZ alone is not enough to get a result when the country is not available.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, null /* countryIsoCode */,
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, null /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(EMPTY_TIME_ZONE_SUGGESTION, actualSuggestion);
         }
 
         // Country + NITZ is enough for a unique time zone detection result for this scenario.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
@@ -170,9 +174,9 @@
             // We use an NITZ from CZ to generate an NITZ signal with a bad offset.
             TimestampedValue<NitzData> badNitzSignal =
                     CZECHIA_SCENARIO.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion = EMPTY_TIME_ZONE_SUGGESTION;
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion = EMPTY_TIME_ZONE_SUGGESTION;
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     badNitzSignal);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
@@ -191,50 +195,45 @@
         // Country won't be enough to get a quality result for time zone detection but a suggestion
         // will be made.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
 
         // NITZ with a "" country code is interpreted as a test network so only offset is used
         // to get a match.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, "" /* countryIsoCode */,
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, "" /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
-            assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(SLOT_INDEX, actualSuggestion.getSlotIndex());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
         }
 
         // NITZ alone is not enough to get a result when the country is not available.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, null /* countryIsoCode */,
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, null /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(EMPTY_TIME_ZONE_SUGGESTION, actualSuggestion);
         }
 
         // Country + NITZ is not enough for a unique time zone detection result for this scenario.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
-            assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(SLOT_INDEX, actualSuggestion.getSlotIndex());
+            assertEquals(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
             List<String> allowedZoneIds = Arrays.asList(NON_UNIQUE_US_ZONE_SCENARIO_ZONES);
             assertTrue(allowedZoneIds.contains(actualSuggestion.getZoneId()));
         }
@@ -245,9 +244,9 @@
             // We use an NITZ from CZ to generate an NITZ signal with a bad offset.
             TimestampedValue<NitzData> badNitzSignal =
                     CZECHIA_SCENARIO.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion = EMPTY_TIME_ZONE_SUGGESTION;
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion = EMPTY_TIME_ZONE_SUGGESTION;
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     badNitzSignal);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
@@ -265,52 +264,49 @@
 
         // Country alone is enough to guess the time zone.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
 
         // NITZ with a "" country code is interpreted as a test network so only offset is used
         // to get a match.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, "" /* countryIsoCode */,
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, "" /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
-            assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(SLOT_INDEX, actualSuggestion.getSlotIndex());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
 
         }
 
         // NITZ alone is not enough to get a result when the country is not available.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, null /* countryIsoCode */,
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, null /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(EMPTY_TIME_ZONE_SUGGESTION, actualSuggestion);
         }
 
         // Country + NITZ is enough for both time + time zone detection.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
@@ -321,15 +317,15 @@
             // We use an NITZ from Czechia to generate an NITZ signal with a bad offset.
             TimestampedValue<NitzData> badNitzSignal =
                     CZECHIA_SCENARIO.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     badNitzSignal);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
@@ -346,53 +342,50 @@
 
         // Country alone is enough to guess the time zone.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
 
         // NITZ with a "" country code is interpreted as a test network so only offset is used
         // to get a match.
         {
-            PhoneTimeZoneSuggestion actualSuggestion =
+            TelephonyTimeZoneSuggestion actualSuggestion =
                     mTimeZoneSuggester.getTimeZoneSuggestion(
-                            PHONE_ID, "" /* countryIsoCode */,
+                            SLOT_INDEX, "" /* countryIsoCode */,
                             scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
-            assertEquals(PHONE_ID, actualSuggestion.getPhoneId());
-            assertEquals(PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY,
-                    actualSuggestion.getMatchType());
-            assertEquals(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET,
-                    actualSuggestion.getQuality());
+            assertEquals(SLOT_INDEX, actualSuggestion.getSlotIndex());
+            assertEquals(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY, actualSuggestion.getMatchType());
+            assertEquals(QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, actualSuggestion.getQuality());
 
         }
 
         // NITZ alone is not enough to get a result when the country is not available.
         {
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, null /* countryIsoCode */,
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, null /* countryIsoCode */,
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(EMPTY_TIME_ZONE_SUGGESTION, actualSuggestion);
         }
 
         // Country + NITZ is enough for both time + time zone detection.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime()));
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
@@ -403,15 +396,15 @@
             // We use an NITZ from the US to generate an NITZ signal with a bad offset.
             TimestampedValue<NitzData> badNitzSignal =
                     UNIQUE_US_ZONE_SCENARIO1.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(),
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(),
                     badNitzSignal);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
@@ -423,16 +416,15 @@
 
         // Country alone is enough to guess the time zone.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.SINGLE_ZONE);
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
 
@@ -448,8 +440,8 @@
             TimestampedValue<NitzData> badNitzSignal = new TimestampedValue<>(
                     goodNitzSignal.getReferenceTimeMillis(), bogusNitzData);
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), badNitzSignal);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), badNitzSignal);
             assertEquals(EMPTY_TIME_ZONE_SUGGESTION, actualSuggestion);
         }
     }
@@ -460,16 +452,15 @@
 
         // Country alone is not enough to guess the time zone.
         {
-            PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                    new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedTimeZoneSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedTimeZoneSuggestion.setMatchType(
-                    PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedTimeZoneSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+            TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
         }
 
@@ -485,8 +476,8 @@
             TimestampedValue<NitzData> badNitzSignal = new TimestampedValue<>(
                     goodNitzSignal.getReferenceTimeMillis(), bogusNitzData);
 
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), badNitzSignal);
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), badNitzSignal);
             assertEquals(EMPTY_TIME_ZONE_SUGGESTION, actualSuggestion);
         }
     }
@@ -512,14 +503,15 @@
         TimestampedValue<NitzData> emulatorNitzSignal = new TimestampedValue<>(
                 originalNitzSignal.getReferenceTimeMillis(), emulatorNitzData);
 
-        PhoneTimeZoneSuggestion expectedTimeZoneSuggestion =
-                new PhoneTimeZoneSuggestion(PHONE_ID);
-        expectedTimeZoneSuggestion.setZoneId(emulatorTimeZoneId);
-        expectedTimeZoneSuggestion.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-        expectedTimeZoneSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
+        TelephonyTimeZoneSuggestion expectedTimeZoneSuggestion =
+                new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                        .setZoneId(emulatorTimeZoneId)
+                        .setMatchType(MATCH_TYPE_EMULATOR_ZONE_ID)
+                        .setQuality(QUALITY_SINGLE_ZONE)
+                        .build();
 
-        PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                PHONE_ID, scenario.getNetworkCountryIsoCode(), emulatorNitzSignal);
+        TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                SLOT_INDEX, scenario.getNetworkCountryIsoCode(), emulatorNitzSignal);
         assertEquals(expectedTimeZoneSuggestion, actualSuggestion);
     }
 
@@ -529,12 +521,15 @@
         // countryIsoCode.
         {
             Scenario scenario = NEW_ZEALAND_DEFAULT_SCENARIO;
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID);
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion expectedSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
 
@@ -543,12 +538,15 @@
             Scenario scenario = NEW_ZEALAND_DEFAULT_SCENARIO;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
+            TelephonyTimeZoneSuggestion expectedSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
 
@@ -557,12 +555,15 @@
             Scenario scenario = NEW_ZEALAND_OTHER_SCENARIO;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
+            TelephonyTimeZoneSuggestion expectedSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
 
@@ -573,12 +574,15 @@
             // Use a scenario that has a different offset than NZ to generate the NITZ signal.
             TimestampedValue<NitzData> nitzSignal =
                     CZECHIA_SCENARIO.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID);
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
+            TelephonyTimeZoneSuggestion expectedSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(NEW_ZEALAND_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
     }
@@ -589,13 +593,15 @@
         // we cannot get a zone only from the countryIsoCode.
         {
             Scenario scenario = UNIQUE_US_ZONE_SCENARIO1;
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(US_COUNTRY_DEFAULT_ZONE_ID);
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-            expectedSuggestion.setQuality(
-                    PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
+            TelephonyTimeZoneSuggestion expectedSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(US_COUNTRY_DEFAULT_ZONE_ID)
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                            .setQuality(QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), null /* nitzSignal */);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
 
@@ -604,12 +610,15 @@
             Scenario scenario = UNIQUE_US_ZONE_SCENARIO1;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
+            TelephonyTimeZoneSuggestion expectedSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
 
@@ -618,12 +627,15 @@
             Scenario scenario = UNIQUE_US_ZONE_SCENARIO2;
             TimestampedValue<NitzData> nitzSignal =
                     scenario.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = new PhoneTimeZoneSuggestion(PHONE_ID);
-            expectedSuggestion.setZoneId(scenario.getTimeZoneId());
-            expectedSuggestion.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET);
-            expectedSuggestion.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
+            TelephonyTimeZoneSuggestion expectedSuggestion =
+                    new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX)
+                            .setZoneId(scenario.getTimeZoneId())
+                            .setMatchType(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET)
+                            .setQuality(QUALITY_SINGLE_ZONE)
+                            .build();
+
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
 
@@ -635,9 +647,9 @@
             // Use a scenario that has a different offset than the US to generate the NITZ signal.
             TimestampedValue<NitzData> nitzSignal =
                     CZECHIA_SCENARIO.createNitzSignal(mFakeDeviceState.elapsedRealtime());
-            PhoneTimeZoneSuggestion expectedSuggestion = EMPTY_TIME_ZONE_SUGGESTION;
-            PhoneTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
-                    PHONE_ID, scenario.getNetworkCountryIsoCode(), nitzSignal);
+            TelephonyTimeZoneSuggestion expectedSuggestion = EMPTY_TIME_ZONE_SUGGESTION;
+            TelephonyTimeZoneSuggestion actualSuggestion = mTimeZoneSuggester.getTimeZoneSuggestion(
+                    SLOT_INDEX, scenario.getNetworkCountryIsoCode(), nitzSignal);
             assertEquals(expectedSuggestion, actualSuggestion);
         }
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestionTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestionTest.java
deleted file mode 100644
index 54838ae..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/PhoneTimeZoneSuggestionTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2019 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.nitz.service;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import org.junit.Test;
-
-public class PhoneTimeZoneSuggestionTest {
-    private static final int PHONE_ID = 99999;
-
-    @Test
-    public void testEquals() {
-        PhoneTimeZoneSuggestion one = new PhoneTimeZoneSuggestion(PHONE_ID);
-        assertEquals(one, one);
-
-        PhoneTimeZoneSuggestion two = new PhoneTimeZoneSuggestion(PHONE_ID);
-        assertEquals(one, two);
-        assertEquals(two, one);
-
-        PhoneTimeZoneSuggestion three = new PhoneTimeZoneSuggestion(PHONE_ID + 1);
-        assertNotEquals(one, three);
-        assertNotEquals(three, one);
-
-        one.setZoneId("Europe/London");
-        assertNotEquals(one, two);
-        two.setZoneId("Europe/Paris");
-        assertNotEquals(one, two);
-        one.setZoneId(two.getZoneId());
-        assertEquals(one, two);
-
-        one.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-        two.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-        assertNotEquals(one, two);
-        one.setMatchType(PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY);
-        assertEquals(one, two);
-
-        one.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-        two.setQuality(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
-        assertNotEquals(one, two);
-        one.setQuality(PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
-        assertEquals(one, two);
-
-        // DebugInfo must not be considered in equals().
-        one.addDebugInfo("Debug info 1");
-        two.addDebugInfo("Debug info 2");
-        assertEquals(one, two);
-    }
-
-    @Test
-    public void testParcelable() {
-        PhoneTimeZoneSuggestion one = new PhoneTimeZoneSuggestion(PHONE_ID);
-        assertEquals(one, roundTripParcelable(one));
-
-        one.setZoneId("Europe/London");
-        one.setMatchType(PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID);
-        one.setQuality(PhoneTimeZoneSuggestion.SINGLE_ZONE);
-        assertEquals(one, roundTripParcelable(one));
-
-        // DebugInfo should also be stored (but is not checked by equals()
-        one.addDebugInfo("This is debug info");
-        PhoneTimeZoneSuggestion two = roundTripParcelable(one);
-        assertEquals(one.getDebugInfo(), two.getDebugInfo());
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T extends Parcelable> T roundTripParcelable(T one) {
-        Parcel parcel = Parcel.obtain();
-        parcel.writeTypedObject(one, 0);
-        parcel.setDataPosition(0);
-
-        T toReturn = (T) parcel.readTypedObject(PhoneTimeZoneSuggestion.CREATOR);
-        parcel.recycle();
-        return toReturn;
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceTest.java
deleted file mode 100644
index f268501..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/nitz/service/TimeZoneDetectionServiceTest.java
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * Copyright 2019 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.nitz.service;
-
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.EMULATOR_ZONE_ID;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MULTIPLE_ZONES_WITH_SAME_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_AND_OFFSET;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.NETWORK_COUNTRY_ONLY;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.SINGLE_ZONE;
-import static com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.TEST_NETWORK_OFFSET_ONLY;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_HIGH;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_HIGHEST;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_LOW;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_MEDIUM;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_NONE;
-import static com.android.internal.telephony.nitz.service.TimeZoneDetectionService.SCORE_USAGE_THRESHOLD;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.MatchType;
-import com.android.internal.telephony.nitz.service.PhoneTimeZoneSuggestion.Quality;
-import com.android.internal.telephony.nitz.service.TimeZoneDetectionService.QualifiedPhoneTimeZoneSuggestion;
-import com.android.internal.util.IndentingPrintWriter;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedList;
-
-/**
- * White-box unit tests for {@link TimeZoneDetectionService}.
- */
-public class TimeZoneDetectionServiceTest {
-
-    private static final int PHONE1_ID = 10000;
-    private static final int PHONE2_ID = 20000;
-
-    // Suggestion test cases are ordered so that each successive one is of the same or higher score
-    // than the previous.
-    private static final SuggestionTestCase[] TEST_CASES = new SuggestionTestCase[] {
-            newTestCase(NETWORK_COUNTRY_ONLY, MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, SCORE_LOW),
-            newTestCase(NETWORK_COUNTRY_ONLY, MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_MEDIUM),
-            newTestCase(NETWORK_COUNTRY_AND_OFFSET, MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_MEDIUM),
-            newTestCase(NETWORK_COUNTRY_ONLY, SINGLE_ZONE, SCORE_HIGH),
-            newTestCase(NETWORK_COUNTRY_AND_OFFSET, SINGLE_ZONE, SCORE_HIGH),
-            newTestCase(TEST_NETWORK_OFFSET_ONLY, MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_HIGHEST),
-            newTestCase(EMULATOR_ZONE_ID, SINGLE_ZONE, SCORE_HIGHEST),
-    };
-
-    private TimeZoneDetectionService mTimeZoneDetectionService;
-    private FakeTimeZoneDetectionServiceHelper mFakeTimeZoneDetectionServiceHelper;
-
-    @Before
-    public void setUp() {
-        mFakeTimeZoneDetectionServiceHelper = new FakeTimeZoneDetectionServiceHelper();
-        mTimeZoneDetectionService =
-                new TimeZoneDetectionService(mFakeTimeZoneDetectionServiceHelper);
-    }
-
-    @Test
-    public void testEmptySuggestions() {
-        PhoneTimeZoneSuggestion phone1TimeZoneSuggestion = createEmptyPhone1Suggestion();
-        PhoneTimeZoneSuggestion phone2TimeZoneSuggestion = createEmptyPhone2Suggestion();
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true)
-                .initializeTimeZoneSetting(true);
-
-        script.suggestPhoneTimeZone(phone1TimeZoneSuggestion)
-                .verifyTimeZoneNotSet();
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedPhone1ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(phone1TimeZoneSuggestion, SCORE_NONE);
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertNull(mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-
-        script.suggestPhoneTimeZone(phone2TimeZoneSuggestion)
-                .verifyTimeZoneNotSet();
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedPhone2ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(phone2TimeZoneSuggestion, SCORE_NONE);
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedPhone2ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-        // Phone 1 should always beat phone 2, all other things being equal.
-        assertEquals(expectedPhone1ScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-    }
-
-    @Test
-    public void testFirstPlausibleSuggestionAcceptedWhenTimeZoneUninitialized() {
-        SuggestionTestCase testCase =
-                newTestCase(NETWORK_COUNTRY_ONLY, MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, SCORE_LOW);
-        PhoneTimeZoneSuggestion lowQualitySuggestion =
-                testCase.createSuggestion(PHONE1_ID, "America/New_York");
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true);
-
-        // The device is uninitialized.
-        script.initializeTimeZoneSetting(false);
-
-        // The very first suggestion will be taken.
-        script.suggestPhoneTimeZone(lowQualitySuggestion)
-                .verifyTimeZoneSetAndReset(lowQualitySuggestion);
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion, testCase.expectedScore);
-        assertEquals(expectedScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-
-        // Another low quality suggestion will be ignored now that the setting is initialized.
-        PhoneTimeZoneSuggestion lowQualitySuggestion2 =
-                testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
-        script.suggestPhoneTimeZone(lowQualitySuggestion2)
-                .verifyTimeZoneNotSet();
-
-        // Assert internal service state.
-        QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion2 =
-                new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion2, testCase.expectedScore);
-        assertEquals(expectedScoredSuggestion2,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedScoredSuggestion2,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-    }
-
-    @Test
-    public void testTogglingTimeZoneDetection() {
-        Script script = new Script()
-                .initializeTimeZoneSetting(true);
-
-        boolean timeZoneDetectionEnabled = false;
-        script.initializeTimeZoneDetectionEnabled(timeZoneDetectionEnabled);
-
-        for (int i = 0; i < TEST_CASES.length; i++) {
-            SuggestionTestCase testCase = TEST_CASES[i];
-
-            PhoneTimeZoneSuggestion suggestion =
-                    testCase.createSuggestion(PHONE1_ID, "Europe/London");
-            script.suggestPhoneTimeZone(suggestion);
-
-            // When time zone detection is already enabled the suggestion (if it scores highly
-            // enough) should be set immediately.
-            if (timeZoneDetectionEnabled) {
-                if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                    script.verifyTimeZoneSetAndReset(suggestion);
-                } else {
-                    script.verifyTimeZoneNotSet();
-                }
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
-                    new QualifiedPhoneTimeZoneSuggestion(suggestion, testCase.expectedScore);
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Now toggle the time zone detection setting: when it is toggled to on and the most
-            // recent suggestion scores highly enough, the time zone should be set.
-            timeZoneDetectionEnabled = !timeZoneDetectionEnabled;
-            script.timeZoneDetectionEnabled(timeZoneDetectionEnabled);
-            if (timeZoneDetectionEnabled) {
-                if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                    script.verifyTimeZoneSetAndReset(suggestion);
-                } else {
-                    script.verifyTimeZoneNotSet();
-                }
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-        }
-    }
-
-    @Test
-    public void testSuggestionsSinglePhone() {
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true)
-                .initializeTimeZoneSetting(true);
-
-        for (SuggestionTestCase testCase : TEST_CASES) {
-            makePhone1SuggestionAndCheckState(script, testCase);
-        }
-
-        /*
-         * This is the same test as above but the test cases are in
-         * reverse order of their expected score. New suggestions always replace previous ones:
-         * there's effectively no history and so ordering shouldn't make any difference.
-         */
-
-        // Each test case will have the same or lower score than the last.
-        ArrayList<SuggestionTestCase> descendingCasesByScore =
-                new ArrayList<>(Arrays.asList(TEST_CASES));
-        Collections.reverse(descendingCasesByScore);
-
-        for (SuggestionTestCase testCase : descendingCasesByScore) {
-            makePhone1SuggestionAndCheckState(script, testCase);
-        }
-    }
-
-    private void makePhone1SuggestionAndCheckState(Script script, SuggestionTestCase testCase) {
-        String zoneId = "Europe/London";
-        PhoneTimeZoneSuggestion zonePhone1Suggestion = testCase.createSuggestion(PHONE1_ID, zoneId);
-        QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion, testCase.expectedScore);
-
-        script.suggestPhoneTimeZone(zonePhone1Suggestion);
-        if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-            script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
-        } else {
-            script.verifyTimeZoneNotSet();
-        }
-
-        // Assert internal service state.
-        assertEquals(expectedZonePhone1ScoredSuggestion,
-                mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-        assertEquals(expectedZonePhone1ScoredSuggestion,
-                mTimeZoneDetectionService.findBestSuggestionForTests());
-    }
-
-    /**
-     * Tries a set of test cases to see if the phone with the lowest ID is given preference. This
-     * test also confirms that the time zone setting would only be set if a suggestion is of
-     * sufficient quality.
-     */
-    @Test
-    public void testMultiplePhoneSuggestionScoringAndPhoneIdBias() {
-        String[] zoneIds = { "Europe/London", "Europe/Paris" };
-        PhoneTimeZoneSuggestion emptyPhone1Suggestion = createEmptyPhone1Suggestion();
-        PhoneTimeZoneSuggestion emptyPhone2Suggestion = createEmptyPhone2Suggestion();
-        QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone1ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(emptyPhone1Suggestion, SCORE_NONE);
-        QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone2ScoredSuggestion =
-                new QualifiedPhoneTimeZoneSuggestion(emptyPhone2Suggestion, SCORE_NONE);
-
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true)
-                .initializeTimeZoneSetting(true)
-                // Initialize the latest suggestions as empty so we don't need to worry about nulls
-                // below for the first loop.
-                .suggestPhoneTimeZone(emptyPhone1Suggestion)
-                .suggestPhoneTimeZone(emptyPhone2Suggestion)
-                .resetState();
-
-        for (SuggestionTestCase testCase : TEST_CASES) {
-            PhoneTimeZoneSuggestion zonePhone1Suggestion =
-                    testCase.createSuggestion(PHONE1_ID, zoneIds[0]);
-            PhoneTimeZoneSuggestion zonePhone2Suggestion =
-                    testCase.createSuggestion(PHONE2_ID, zoneIds[1]);
-            QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
-                    new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion,
-                            testCase.expectedScore);
-            QualifiedPhoneTimeZoneSuggestion expectedZonePhone2ScoredSuggestion =
-                    new QualifiedPhoneTimeZoneSuggestion(zonePhone2Suggestion,
-                            testCase.expectedScore);
-
-            // Start the test by making a suggestion for phone 1.
-            script.suggestPhoneTimeZone(zonePhone1Suggestion);
-            if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedEmptyPhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Phone 2 then makes an identical suggestion. Phone 1's suggestion should still "win"
-            // if it is above the required threshold.
-            script.suggestPhoneTimeZone(zonePhone2Suggestion);
-            if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedZonePhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-            // Phone 1 should always beat phone 2, all other things being equal.
-            assertEquals(expectedZonePhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Withdrawing phone 1's suggestion should leave phone 2 as the new winner. Since the
-            // zoneId is different, the time zone setting should be updated.
-            script.suggestPhoneTimeZone(emptyPhone1Suggestion);
-            if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
-                script.verifyTimeZoneSetAndReset(zonePhone2Suggestion);
-            } else {
-                script.verifyTimeZoneNotSet();
-            }
-
-            // Assert internal service state.
-            assertEquals(expectedEmptyPhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedZonePhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-            assertEquals(expectedZonePhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.findBestSuggestionForTests());
-
-            // Reset the state for the next loop.
-            script.suggestPhoneTimeZone(emptyPhone2Suggestion)
-                    .verifyTimeZoneNotSet();
-            assertEquals(expectedEmptyPhone1ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE1_ID));
-            assertEquals(expectedEmptyPhone2ScoredSuggestion,
-                    mTimeZoneDetectionService.getLatestPhoneSuggestion(PHONE2_ID));
-        }
-    }
-
-    /**
-     * The {@link TimeZoneDetectionService.Helper} is left to detect whether changing the the time
-     * zone is actually necessary. This test proves that the service doesn't assume it knows the
-     * current setting.
-     */
-    @Test
-    public void testTimeZoneDetectionServiceDoesNotAssumeCurrentSetting() {
-        Script script = new Script()
-                .initializeTimeZoneDetectionEnabled(true);
-
-        SuggestionTestCase testCase =
-                newTestCase(NETWORK_COUNTRY_AND_OFFSET, SINGLE_ZONE, SCORE_HIGH);
-        PhoneTimeZoneSuggestion losAngelesSuggestion =
-                testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
-        PhoneTimeZoneSuggestion newYorkSuggestion =
-                testCase.createSuggestion(PHONE1_ID, "America/New_York");
-
-        // Initialization.
-        script.suggestPhoneTimeZone(losAngelesSuggestion)
-                .verifyTimeZoneSetAndReset(losAngelesSuggestion);
-        // Suggest it again - it should be set.
-        script.suggestPhoneTimeZone(losAngelesSuggestion)
-                .verifyTimeZoneSetAndReset(losAngelesSuggestion);
-
-        // Toggling time zone detection should set it.
-        script.timeZoneDetectionEnabled(false)
-                .timeZoneDetectionEnabled(true)
-                .verifyTimeZoneSetAndReset(losAngelesSuggestion);
-
-        // Simulate a user turning detection off, a new suggestion being made, and the user turning
-        // it on again.
-        script.timeZoneDetectionEnabled(false)
-                .suggestPhoneTimeZone(newYorkSuggestion)
-                .verifyTimeZoneNotSet();
-        // Latest suggestion should be used.
-        script.timeZoneDetectionEnabled(true)
-                .verifyTimeZoneSetAndReset(newYorkSuggestion);
-    }
-
-    private static PhoneTimeZoneSuggestion createEmptyPhone1Suggestion() {
-        return new PhoneTimeZoneSuggestion(PHONE1_ID);
-    }
-
-    private static PhoneTimeZoneSuggestion createEmptyPhone2Suggestion() {
-        return new PhoneTimeZoneSuggestion(PHONE2_ID);
-    }
-
-    class FakeTimeZoneDetectionServiceHelper implements TimeZoneDetectionService.Helper {
-
-        private Listener mListener;
-        private boolean mTimeZoneDetectionEnabled;
-        private boolean mTimeZoneInitialized = false;
-        private TestState<PhoneTimeZoneSuggestion> mTimeZoneSuggestion = new TestState<>();
-
-        @Override
-        public void setListener(Listener listener) {
-            this.mListener = listener;
-        }
-
-        @Override
-        public boolean isTimeZoneDetectionEnabled() {
-            return mTimeZoneDetectionEnabled;
-        }
-
-        @Override
-        public boolean isTimeZoneSettingInitialized() {
-            return mTimeZoneInitialized;
-        }
-
-        @Override
-        public void setDeviceTimeZoneFromSuggestion(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-            mTimeZoneInitialized = true;
-            mTimeZoneSuggestion.set(timeZoneSuggestion);
-        }
-
-        @Override
-        public void dumpState(PrintWriter pw) {
-            // No-op for fake
-        }
-
-        @Override
-        public void dumpLogs(IndentingPrintWriter ipw) {
-            // No-op for fake
-        }
-
-        void initializeTimeZoneDetectionEnabled(boolean enabled) {
-            mTimeZoneDetectionEnabled = enabled;
-        }
-
-        void initializeTimeZone(boolean initialized) {
-            mTimeZoneInitialized = initialized;
-        }
-
-        void simulateTimeZoneDetectionEnabled(boolean enabled) {
-            mTimeZoneDetectionEnabled = enabled;
-            mListener.onTimeZoneDetectionChange(enabled);
-        }
-
-        void assertTimeZoneNotSet() {
-            mTimeZoneSuggestion.assertHasNotBeenSet();
-        }
-
-        void assertTimeZoneSuggested(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-            mTimeZoneSuggestion.assertHasBeenSet();
-            mTimeZoneSuggestion.assertChangeCount(1);
-            mTimeZoneSuggestion.assertLatestEquals(timeZoneSuggestion);
-        }
-
-        void commitAllChanges() {
-            mTimeZoneSuggestion.commitLatest();
-        }
-    }
-
-    /** Some piece of state that tests want to track. */
-    private static class TestState<T> {
-        private T mInitialValue;
-        private LinkedList<T> mValues = new LinkedList<>();
-
-        void init(T value) {
-            mValues.clear();
-            mInitialValue = value;
-        }
-
-        void set(T value) {
-            mValues.addFirst(value);
-        }
-
-        boolean hasBeenSet() {
-            return mValues.size() > 0;
-        }
-
-        void assertHasNotBeenSet() {
-            assertFalse(hasBeenSet());
-        }
-
-        void assertHasBeenSet() {
-            assertTrue(hasBeenSet());
-        }
-
-        void commitLatest() {
-            if (hasBeenSet()) {
-                mInitialValue = mValues.getLast();
-                mValues.clear();
-            }
-        }
-
-        void assertLatestEquals(T expected) {
-            assertEquals(expected, getLatest());
-        }
-
-        void assertChangeCount(int expectedCount) {
-            assertEquals(expectedCount, mValues.size());
-        }
-
-        public T getLatest() {
-            if (hasBeenSet()) {
-                return mValues.getFirst();
-            }
-            return mInitialValue;
-        }
-    }
-
-    /**
-     * A "fluent" class allows reuse of code in tests: initialization, simulation and verification
-     * logic.
-     */
-    private class Script {
-
-        Script initializeTimeZoneDetectionEnabled(boolean enabled) {
-            mFakeTimeZoneDetectionServiceHelper.initializeTimeZoneDetectionEnabled(enabled);
-            return this;
-        }
-
-        Script initializeTimeZoneSetting(boolean initialized) {
-            mFakeTimeZoneDetectionServiceHelper.initializeTimeZone(initialized);
-            return this;
-        }
-
-        Script timeZoneDetectionEnabled(boolean timeZoneDetectionEnabled) {
-            mFakeTimeZoneDetectionServiceHelper.simulateTimeZoneDetectionEnabled(
-                    timeZoneDetectionEnabled);
-            return this;
-        }
-
-        /** Simulates the time zone detection service receiving a phone-originated suggestion. */
-        Script suggestPhoneTimeZone(PhoneTimeZoneSuggestion phoneTimeZoneSuggestion) {
-            mTimeZoneDetectionService.suggestPhoneTimeZone(phoneTimeZoneSuggestion);
-            return this;
-        }
-
-        Script verifyTimeZoneNotSet() {
-            mFakeTimeZoneDetectionServiceHelper.assertTimeZoneNotSet();
-            return this;
-        }
-
-        Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion timeZoneSuggestion) {
-            mFakeTimeZoneDetectionServiceHelper.assertTimeZoneSuggested(timeZoneSuggestion);
-            mFakeTimeZoneDetectionServiceHelper.commitAllChanges();
-            return this;
-        }
-
-        Script resetState() {
-            mFakeTimeZoneDetectionServiceHelper.commitAllChanges();
-            return this;
-        }
-    }
-
-    private static class SuggestionTestCase {
-        public final int matchType;
-        public final int quality;
-        public final int expectedScore;
-
-        SuggestionTestCase(int matchType, int quality, int expectedScore) {
-            this.matchType = matchType;
-            this.quality = quality;
-            this.expectedScore = expectedScore;
-        }
-
-        private PhoneTimeZoneSuggestion createSuggestion(int phoneId, String zoneId) {
-            PhoneTimeZoneSuggestion suggestion = new PhoneTimeZoneSuggestion(phoneId);
-            suggestion.setZoneId(zoneId);
-            suggestion.setMatchType(matchType);
-            suggestion.setQuality(quality);
-            return suggestion;
-        }
-    }
-
-    private static SuggestionTestCase newTestCase(
-            @MatchType int matchType, @Quality int quality, int expectedScore) {
-        return new SuggestionTestCase(matchType, quality, expectedScore);
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccRecordsTest.java
index 666da41..d668536 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccRecordsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccRecordsTest.java
@@ -33,6 +33,8 @@
 import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.*;
 
+import android.content.Context;
+import android.os.AsyncResult;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.util.Pair;
@@ -107,4 +109,19 @@
         pair = mIccRecords.retrievePendingTransaction(key);
         assertNull(pair);
     }
+
+    @Test
+    public void testGetSmsCapacityOnIcc() {
+        // set the number of records to 500
+        int[] records = new int[3];
+        records[2] = 500;
+        Message fetchCapacityDone = mIccRecords.obtainMessage(
+                IccRecords.EVENT_GET_SMS_RECORD_SIZE_DONE);
+        AsyncResult.forMessage(fetchCapacityDone, records, null);
+        fetchCapacityDone.sendToTarget();
+
+        // verify whether the count is 500
+        waitForLastHandlerAction(mIccRecords);
+        assertEquals(mIccRecords.getSmsCapacityOnIcc(), 500);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
index 80353fe..b383bfa 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
@@ -30,6 +30,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.TelephonyTest;
 
 import org.junit.After;
@@ -256,6 +257,38 @@
         assertEquals(0, mUiccCarrierPrivilegeRules.getPackageNames().size());
     }
 
+    @Test
+    @SmallTest
+    public void testRetryARAM_shouldRetry() {
+        AsyncResult ar1 = new AsyncResult(
+                null,
+                new int[]{0, 105, -123},
+                new CommandException(CommandException.Error.NO_SUCH_ELEMENT));
+        assertTrue(mUiccCarrierPrivilegeRules.shouldRetry(ar1, 0));
+
+        AsyncResult ar2 = new AsyncResult(
+                null,
+                new int[]{0},
+                new CommandException(CommandException.Error.MISSING_RESOURCE));
+        assertTrue(mUiccCarrierPrivilegeRules.shouldRetry(ar2, 0));
+
+        AsyncResult ar3 = new AsyncResult(
+                null,
+                new int[]{0, 105, 153},
+                new CommandException(CommandException.Error.INTERNAL_ERR));
+        assertTrue(mUiccCarrierPrivilegeRules.shouldRetry(ar3, 0));
+    }
+
+    @Test
+    @SmallTest
+    public void testRetryARAM_shouldNotRetry() {
+        AsyncResult ar = new AsyncResult(
+                null,
+                new int[]{0, 106, -126},
+                new CommandException(CommandException.Error.NO_SUCH_ELEMENT));
+        assertTrue(!mUiccCarrierPrivilegeRules.shouldRetry(ar, 0));
+    }
+
     private static final String ARAM = "A00000015141434C00";
     private static final String ARAD = "A00000015144414300";
     private static final String PKCS15_AID = "A000000063504B43532D3135";
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
index 804bdf1..e518f3e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
@@ -39,7 +39,6 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.uicc.euicc.EuiccCard;
 
@@ -52,6 +51,7 @@
 
 import java.util.ArrayList;
 
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class UiccControllerTest extends TelephonyTest {
@@ -109,8 +109,7 @@
         // for testing we pretend slotIndex is set. In reality it would be invalid on older versions
         // (before 1.2) of hal
         mIccCardStatus.physicalSlotIndex = 0;
-        mUiccControllerUT = UiccController.make(mContext,
-            new CommandsInterface[]{mSimulatedCommands});
+        mUiccControllerUT = UiccController.make(mContext);
         // reset sLastSlotStatus so that onGetSlotStatusDone always sees a change in the slot status
         mUiccControllerUT.sLastSlotStatus = null;
         processAllMessages();
@@ -131,8 +130,7 @@
                 com.android.internal.R.array.non_removable_euicc_slots,
                 nonRemovableEuiccSlots);
         replaceInstance(UiccController.class, "mInstance", null, null);
-        mUiccControllerUT = UiccController.make(mContext,
-            new CommandsInterface[]{mSimulatedCommands});
+        mUiccControllerUT = UiccController.make(mContext);
         processAllMessages();
     }
 
@@ -595,4 +593,42 @@
         assertEquals(mUiccControllerUT.convertToPublicCardId(eidForRemovableEuicc),
                 mUiccControllerUT.getCardIdForDefaultEuicc());
     }
+
+    /**
+     * When IccCardStatus is received, if the EID is known from previous APDU, use it to set the
+     * mDefaultEuiccCardId.
+     */
+    @Test
+    public void testEidFromPreviousApduSetsDefaultEuicc() {
+        // Give UiccController a real context so it can use shared preferences
+        mUiccControllerUT.mContext = InstrumentationRegistry.getContext();
+
+        // Mock out UiccSlots
+        mUiccControllerUT.mUiccSlots[0] = mMockSlot;
+        doReturn(true).when(mMockSlot).isEuicc();
+        doReturn(null).when(mMockSlot).getUiccCard();
+        doReturn("123451234567890").when(mMockSlot).getIccId();
+        doReturn(false).when(mMockSlot).isRemovable();
+
+        // If APDU has already happened, the EuiccCard already knows EID
+        String knownEidFromApdu = "A1B2C3D4E5";
+        doReturn(mMockEuiccCard).when(mMockSlot).getUiccCard();
+        doReturn(knownEidFromApdu).when(mMockEuiccCard).getEid();
+
+        // simulate card status loaded so that the UiccController sets the card ID
+        IccCardStatus ics = new IccCardStatus();
+        ics.setCardState(1 /* present */);
+        ics.setUniversalPinState(3 /* disabled */);
+        ics.atr = "abcdef0123456789abcdef";
+        ics.iccid = "123451234567890";
+        // the IccCardStatus does not contain EID, but it is known from previous APDU
+        ics.eid = null;
+        AsyncResult ar = new AsyncResult(null, ics, null);
+        Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar);
+        mUiccControllerUT.handleMessage(msg);
+
+        // since EID is known and we've gotten card status, the default eUICC card ID should be set
+        assertEquals(mUiccControllerUT.convertToPublicCardId(knownEidFromApdu),
+                mUiccControllerUT.getCardIdForDefaultEuicc());
+    }
 }