Merge "Add missed satellite metrics case" into main
diff --git a/flags/data.aconfig b/flags/data.aconfig
index 260d983..0bcd4bd 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -12,4 +12,11 @@
   namespace: "telephony"
   description: "Relax handover tear down if the device is currently in voice call."
   bug: "270895912"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "allow_mmtel_in_non_vops"
+  namespace: "telephony"
+  description: "Allow bring up MMTEL in nonVops area specified by carrier config."
+  bug: "241198464"
+}
diff --git a/flags/ims.aconfig b/flags/ims.aconfig
index b41ef4d..4f06049 100644
--- a/flags/ims.aconfig
+++ b/flags/ims.aconfig
@@ -5,4 +5,11 @@
     namespace: "telephony"
     description: "This flag controls Conference’s hold & unHold operation changed to send a message"
     bug:"288002989"
+}
+
+flag {
+    name: "ignore_already_terminated_incoming_call_before_registering_listener"
+    namespace: "telephony"
+    description: "This flag ignores the incoming call by throwing an exception if the call was already terminated before the framework registers the listener for the incoming call"
+    bug:"289461637"
 }
\ No newline at end of file
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 722cb7c..993aa4d 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -427,6 +427,8 @@
     optional int64 video_available_millis = 10;
     optional int64 ut_capable_millis = 11;
     optional int64 ut_available_millis = 12;
+    optional int64 registering_millis = 13;
+    optional int64 unregistered_millis = 14;
 
     // Internal use only
     optional int64 last_used_millis = 10001;
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 22ad593..950ac10 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -31,6 +31,7 @@
 import android.telephony.Annotation.NetCapability;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.CarrierConfigManager;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
@@ -46,6 +47,7 @@
 import com.android.internal.telephony.data.DataNetworkController.HandoverRule;
 import com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryRule;
 import com.android.internal.telephony.data.DataRetryManager.DataSetupRetryRule;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
@@ -259,6 +261,7 @@
     private @NonNull final Phone mPhone;
     private @NonNull final String mLogTag;
 
+    @NonNull private final FeatureFlags mFeatureFlags;
     private @NonNull final CarrierConfigManager mCarrierConfigManager;
     private @NonNull PersistableBundle mCarrierConfig = null;
     private @NonNull Resources mResources = null;
@@ -295,6 +298,9 @@
     private @NonNull final List<HandoverRule> mHandoverRuleList = new ArrayList<>();
     /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/
     private boolean mShouldKeepNetworkUpInNonVops = false;
+    /** The set of network types that enable VOPS even in non VOPS area. */
+    @NonNull private final @CarrierConfigManager.Ims.NetworkType List<Integer>
+            mEnabledVopsNetworkTypesInNonVops = new ArrayList<>();
     /**
      * A map of network types to the estimated downlink values by signal strength 0 - 4 for that
      * network type
@@ -309,9 +315,11 @@
      * @param looper The looper to be used by the handler. Currently the handler thread is the
      * phone process's main thread.
      */
-    public DataConfigManager(@NonNull Phone phone, @NonNull Looper looper) {
+    public DataConfigManager(@NonNull Phone phone, @NonNull Looper looper,
+            @NonNull FeatureFlags featureFlags) {
         super(looper);
         mPhone = phone;
+        mFeatureFlags = featureFlags;
         mLogTag = "DCM-" + mPhone.getPhoneId();
         log("DataConfigManager created.");
 
@@ -666,6 +674,11 @@
         synchronized (this) {
             mShouldKeepNetworkUpInNonVops = mCarrierConfig.getBoolean(CarrierConfigManager
                     .Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL);
+            int[] allowedNetworkTypes = mCarrierConfig.getIntArray(
+                    CarrierConfigManager.Ims.KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY);
+            if (allowedNetworkTypes != null) {
+                Arrays.stream(allowedNetworkTypes).forEach(mEnabledVopsNetworkTypesInNonVops::add);
+            }
         }
     }
 
@@ -684,9 +697,29 @@
         return Collections.unmodifiableSet(mCapabilitiesExemptFromSingleDataList);
     }
 
-    /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/
-    public boolean shouldKeepNetworkUpInNonVops() {
-        return mShouldKeepNetworkUpInNonVops;
+    /**
+     * @param regState The modem reported data registration state.
+     * @return {@code true} if should keep IMS network in case of moving to non VOPS area.
+     */
+    public boolean shouldKeepNetworkUpInNonVops(@NetworkRegistrationInfo.RegistrationState
+            int regState) {
+        return mShouldKeepNetworkUpInNonVops || allowBringUpNetworkInNonVops(regState);
+    }
+
+    /**
+     * @param regState The modem reported data registration state.
+     * @return {@code true} if allow bring up IMS network in case of moving to non VOPS area.
+     */
+    public boolean allowBringUpNetworkInNonVops(@NetworkRegistrationInfo.RegistrationState
+            int regState) {
+        if (!mFeatureFlags.allowMmtelInNonVops()) return false;
+        int networkType = -1;
+        if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
+            networkType = CarrierConfigManager.Ims.NETWORK_TYPE_HOME;
+        } else if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) {
+            networkType = CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING;
+        }
+        return mEnabledVopsNetworkTypesInNonVops.contains(networkType);
     }
 
     /** {@code True} requires ping test to pass on the target slot before switching to it.*/
@@ -1423,7 +1456,8 @@
         pw.println("Capabilities exempt from single PDN=" + mCapabilitiesExemptFromSingleDataList
                 .stream().map(DataUtils::networkCapabilityToString)
                 .collect(Collectors.joining(",")));
-        pw.println("mShouldKeepNetworkUpInNoVops=" + mShouldKeepNetworkUpInNonVops);
+        pw.println("mShouldKeepNetworkUpInNonVops=" + mShouldKeepNetworkUpInNonVops);
+        pw.println("mEnabledVopsNetworkTypesInNonVops=" + mEnabledVopsNetworkTypesInNonVops);
         pw.println("isPingTestBeforeAutoDataSwitchRequired="
                 + isPingTestBeforeAutoDataSwitchRequired());
         pw.println("Unmetered network types=" + String.join(",", mUnmeteredNetworkTypes));
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index f3bb6c1..0c5c9cb 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -99,6 +99,7 @@
 import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback;
 import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback;
 import com.android.internal.telephony.data.TelephonyNetworkAgent.TelephonyNetworkAgentCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.metrics.DataCallSessionStats;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.util.ArrayUtils;
@@ -440,9 +441,9 @@
             // Connectivity service will support NOT_METERED as a mutable and requestable
             // capability.
             NetworkCapabilities.NET_CAPABILITY_NOT_METERED,
-            // Even though MMTEL is an immutable capability, we still make it an mutable capability
-            // here before we have a better solution to deal with network transition from VoPS
-            // to non-VoPS network.
+            // Dynamically add and remove MMTEL capability when network transition between VoPS
+            // and non-VoPS network if the request is not MMTEL. For MMTEL, we retain the capability
+            // to prevent immediate tear down.
             NetworkCapabilities.NET_CAPABILITY_MMTEL
     );
 
@@ -490,6 +491,9 @@
     /** The phone instance. */
     private final @NonNull Phone mPhone;
 
+    /** Feature flags */
+    private final @NonNull FeatureFlags mFlags;
+
     /**
      * The subscription id. This is assigned when the network is created, and not supposed to
      * change afterwards.
@@ -897,7 +901,7 @@
      * @param dataAllowedReason The reason that why setting up this data network is allowed.
      * @param callback The callback to receives data network state update.
      */
-    public DataNetwork(@NonNull Phone phone, @NonNull Looper looper,
+    public DataNetwork(@NonNull Phone phone, FeatureFlags featureFlags, @NonNull Looper looper,
             @NonNull SparseArray<DataServiceManager> dataServiceManagers,
             @NonNull DataProfile dataProfile,
             @NonNull NetworkRequestList networkRequestList,
@@ -911,6 +915,7 @@
         initializeStateMachine();
 
         mPhone = phone;
+        mFlags = featureFlags;
         mSubId = phone.getSubId();
         mRil = mPhone.mCi;
         mLinkProperties = new LinkProperties();
@@ -2141,30 +2146,34 @@
             }
         }
 
-        // Once we set the MMTEL capability, we should never remove it because it's an immutable
+        // If MMTEL capability is requested, we should not remove it because it's an immutable
         // capability defined by connectivity service. When the device enters from VoPS to non-VoPS,
         // we should perform grace tear down from data network controller if needed.
-        if (mNetworkCapabilities != null
-                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)) {
-            // Previous capability has MMTEL, so add it again.
+        if (hasNetworkCapabilityInNetworkRequests(NetworkCapabilities.NET_CAPABILITY_MMTEL)) {
+            // Request has MMTEL, add it again so the network won't be unwanted by connectivity.
             builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-        } else {
+        } else if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+            // Request has IMS capability only.
             // Always add MMTEL capability on IMS network unless network explicitly indicates VoPS
             // not supported.
-            if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) {
-                builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-                if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
-                    NetworkRegistrationInfo nri = getNetworkRegistrationInfo();
-                    if (nri != null) {
-                        DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
-                        // Check if the network is non-VoPS.
-                        if (dsri != null && dsri.getVopsSupportInfo() != null
-                                && !dsri.getVopsSupportInfo().isVopsSupported()
-                                && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) {
-                            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-                        }
-                        log("updateNetworkCapabilities: dsri=" + dsri);
+            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
+            if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
+                NetworkRegistrationInfo nri = getNetworkRegistrationInfo();
+                if (nri != null) {
+                    DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
+                    // Check if the network is non-VoPS.
+                    if (dsri != null && dsri.getVopsSupportInfo() != null
+                            && !dsri.getVopsSupportInfo().isVopsSupported()
+                            // Reflect the actual MMTEL if flag on.
+                            && (mFlags.allowMmtelInNonVops()
+                            // Deceive Connectivity service to satisfy an MMTEL request, this should
+                            // be useless because we reach here if no MMTEL request, then removing
+                            // MMTEL capability shouldn't have any impacts.
+                            || !mDataConfigManager.shouldKeepNetworkUpInNonVops(
+                                    nri.getNetworkRegistrationState()))) {
+                        builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
                     }
+                    log("updateNetworkCapabilities: dsri=" + dsri);
                 }
             }
         }
@@ -2721,7 +2730,7 @@
     public boolean shouldDelayImsTearDownDueToInCall() {
         return mDataConfigManager.isImsDelayTearDownUntilVoiceCallEndEnabled()
                 && mNetworkCapabilities != null
-                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)
+                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                 && mPhone.getImsPhone() != null
                 && mPhone.getImsPhone().getCallTracker().getState()
                 != PhoneConstants.State.IDLE;
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 5bdef27..2d91967 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -813,7 +813,7 @@
             mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, transport));
         }
 
-        mDataConfigManager = new DataConfigManager(mPhone, looper);
+        mDataConfigManager = new DataConfigManager(mPhone, looper, featureFlags);
 
         // ========== Anomaly counters ==========
         mImsThrottleCounter = new SlidingWindowEventCounter(
@@ -1529,7 +1529,9 @@
             if (nri != null) {
                 DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
                 if (dsri != null && dsri.getVopsSupportInfo() != null
-                        && !dsri.getVopsSupportInfo().isVopsSupported()) {
+                        && !dsri.getVopsSupportInfo().isVopsSupported()
+                        && !mDataConfigManager.allowBringUpNetworkInNonVops(
+                                nri.getNetworkRegistrationState())) {
                     evaluation.addDataDisallowedReason(DataDisallowedReason.VOPS_NOT_SUPPORTED);
                 }
             }
@@ -1791,6 +1793,8 @@
             }
         }
 
+        // It's recommended for IMS service not requesting MMTEL capability, so that MMTEL
+        // capability is dynamically added when moving between vops and nonvops area.
         boolean vopsIsRequired = dataNetwork.hasNetworkCapabilityInNetworkRequests(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL);
 
@@ -1813,7 +1817,8 @@
                         DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
                         if (dsri != null && dsri.getVopsSupportInfo() != null
                                 && !dsri.getVopsSupportInfo().isVopsSupported()
-                                && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) {
+                                && !mDataConfigManager.shouldKeepNetworkUpInNonVops(
+                                        nri.getNetworkRegistrationState())) {
                             evaluation.addDataDisallowedReason(
                                     DataDisallowedReason.VOPS_NOT_SUPPORTED);
                         }
@@ -1993,6 +1998,8 @@
                 }
 
                 // Check if VoPS is required, but the target transport is non-VoPS.
+                // It's recommended for IMS service not requesting MMTEL capability, so that MMTEL
+                // capability is dynamically added when moving between vops and nonvops area.
                 NetworkRequestList networkRequestList =
                         dataNetwork.getAttachedNetworkRequestList();
                 if (networkRequestList.stream().anyMatch(request
@@ -2001,7 +2008,8 @@
                     // Check if the network is non-VoPS.
                     if (dsri != null && dsri.getVopsSupportInfo() != null
                             && !dsri.getVopsSupportInfo().isVopsSupported()
-                            && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) {
+                            && !mDataConfigManager.shouldKeepNetworkUpInNonVops(
+                                    nri.getNetworkRegistrationState())) {
                         dataEvaluation.addDataDisallowedReason(
                                 DataDisallowedReason.VOPS_NOT_SUPPORTED);
                     }
@@ -2545,8 +2553,8 @@
                 + AccessNetworkConstants.transportTypeToString(transport) + " with " + dataProfile
                 + ", and attaching " + networkRequestList.size() + " network requests to it.");
 
-        mDataNetworkList.add(new DataNetwork(mPhone, getLooper(), mDataServiceManagers,
-                dataProfile, networkRequestList, transport, allowedReason,
+        mDataNetworkList.add(new DataNetwork(mPhone, mFeatureFlags, getLooper(),
+                mDataServiceManagers, dataProfile, networkRequestList, transport, allowedReason,
                 new DataNetworkCallback(this::post) {
                     @Override
                     public void onSetupDataFailed(@NonNull DataNetwork dataNetwork,
@@ -3390,7 +3398,8 @@
         }
 
         if (oldNri.getAccessNetworkTechnology() != newNri.getAccessNetworkTechnology()
-                || (!oldNri.isRoaming() && newNri.isRoaming())) {
+                // Some CarrierConfig disallows vops in nonVops area for specified home/roaming.
+                || (oldNri.isRoaming() != newNri.isRoaming())) {
             return true;
         }
 
@@ -3440,7 +3449,8 @@
         if (oldPsNri == null
                 || oldPsNri.getAccessNetworkTechnology() != newPsNri.getAccessNetworkTechnology()
                 || (!oldPsNri.isInService() && newPsNri.isInService())
-                || (oldPsNri.isRoaming() && !newPsNri.isRoaming())) {
+                // Some CarrierConfig allows vops in nonVops area for specified home/roaming.
+                || (oldPsNri.isRoaming() != newPsNri.isRoaming())) {
             return true;
         }
 
diff --git a/src/java/com/android/internal/telephony/metrics/ImsStats.java b/src/java/com/android/internal/telephony/metrics/ImsStats.java
index 427595f..2420602 100644
--- a/src/java/com/android/internal/telephony/metrics/ImsStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ImsStats.java
@@ -197,7 +197,7 @@
     @ImsRegistrationState private int mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED;
 
     private long mLastTimestamp;
-    @Nullable private ImsRegistrationStats mLastRegistrationStats;
+    private ImsRegistrationStats mLastRegistrationStats;
     @TransportType int mLastTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
     // Available features are those reported by ImsService to be available for use.
     private MmTelCapabilities mLastAvailableFeatures = new MmTelCapabilities();
@@ -210,6 +210,10 @@
     public ImsStats(ImsPhone phone) {
         mPhone = phone;
         mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage();
+
+        mLastRegistrationStats = getDefaultImsRegistrationStats();
+        updateImsRegistrationStats();
+        mLastTimestamp = getTimeMillis();
     }
 
     /**
@@ -221,40 +225,46 @@
     public synchronized void conclude() {
         long now = getTimeMillis();
 
-        // Currently not tracking time spent on registering.
-        if (mLastRegistrationState == REGISTRATION_STATE_REGISTERED) {
-            ImsRegistrationStats stats = copyOf(mLastRegistrationStats);
-            long duration = now - mLastTimestamp;
+        long duration = now - mLastTimestamp;
+        if (duration < MIN_REGISTRATION_DURATION_MILLIS) {
+            logw("conclude: discarding transient stats, duration=%d", duration);
+        } else {
+            ImsRegistrationStats stats = copyOfDimensionsOnly(mLastRegistrationStats);
 
-            if (duration < MIN_REGISTRATION_DURATION_MILLIS) {
-                logw("conclude: discarding transient stats, duration=%d", duration);
-            } else {
-                stats.registeredMillis = duration;
+            switch (mLastRegistrationState) {
+                case REGISTRATION_STATE_REGISTERED:
+                    stats.registeredMillis = duration;
 
-                stats.voiceAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
-                stats.videoAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
-                stats.utAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
-                stats.smsAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
+                    stats.voiceAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
+                    stats.videoAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
+                    stats.utAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
+                    stats.smsAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
 
-                MmTelCapabilities lastCapableFeatures =
-                        stats.rat == TelephonyManager.NETWORK_TYPE_IWLAN
-                                ? mLastWlanCapableFeatures
-                                : mLastWwanCapableFeatures;
-                stats.voiceCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
-                stats.videoCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
-                stats.utCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
-                stats.smsCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
-
-                mStorage.addImsRegistrationStats(stats);
+                    MmTelCapabilities lastCapableFeatures =
+                            stats.rat == TelephonyManager.NETWORK_TYPE_IWLAN
+                                    ? mLastWlanCapableFeatures
+                                    : mLastWwanCapableFeatures;
+                    stats.voiceCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
+                    stats.videoCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
+                    stats.utCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
+                    stats.smsCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
+                    break;
+                case REGISTRATION_STATE_REGISTERING:
+                    stats.registeringMillis = duration;
+                    break;
+                case REGISTRATION_STATE_NOT_REGISTERED:
+                    stats.unregisteredMillis = duration;
+                    break;
             }
+            mStorage.addImsRegistrationStats(stats);
         }
 
         mLastTimestamp = now;
@@ -271,7 +281,7 @@
                 (newRat == TelephonyManager.NETWORK_TYPE_IWLAN)
                         ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN
                         : AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
-        if (mLastRegistrationStats != null && mLastRegistrationStats.rat != newRat) {
+        if (mLastRegistrationStats.rat != newRat) {
             mLastRegistrationStats.rat = newRat;
             ratChanged = true;
         }
@@ -308,7 +318,7 @@
         conclude();
 
         mLastTransportType = imsRadioTech;
-        mLastRegistrationStats = getDefaultImsRegistrationStats();
+        updateImsRegistrationStats();
         mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech);
         mLastRegistrationState = REGISTRATION_STATE_REGISTERING;
     }
@@ -318,9 +328,9 @@
         conclude();
 
         mLastTransportType = imsRadioTech;
-        // NOTE: mLastRegistrationStats can be null (no registering phase).
-        if (mLastRegistrationStats == null) {
-            mLastRegistrationStats = getDefaultImsRegistrationStats();
+        // NOTE: status can be unregistered (no registering phase)
+        if (mLastRegistrationState == REGISTRATION_STATE_NOT_REGISTERED) {
+            updateImsRegistrationStats();
         }
         mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech);
         mLastRegistrationState = REGISTRATION_STATE_REGISTERED;
@@ -331,16 +341,14 @@
         conclude();
 
         // Generate end reason atom.
-        // NOTE: mLastRegistrationStats can be null (no registering phase).
         ImsRegistrationTermination termination = new ImsRegistrationTermination();
-        if (mLastRegistrationStats != null) {
+        if (mLastRegistrationState != REGISTRATION_STATE_NOT_REGISTERED) {
             termination.carrierId = mLastRegistrationStats.carrierId;
-            termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat);
         } else {
+            // if the registration state is from unregistered to unregistered.
             termination.carrierId = mPhone.getDefaultPhone().getCarrierId();
-            // We cannot tell whether the registration was intended for WWAN or WLAN
-            termination.ratAtEnd = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
+        termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat);
         termination.isMultiSim = SimSlotState.isMultiSim();
         termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED);
         termination.reasonCode = reasonInfo.getCode();
@@ -351,14 +359,14 @@
 
         // Reset state to unregistered.
         mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED;
-        mLastRegistrationStats = null;
+        mLastRegistrationStats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         mLastAvailableFeatures = new MmTelCapabilities();
     }
 
     /** Updates the RAT when service state changes. */
     public synchronized void onServiceStateChanged(ServiceState state) {
         if (mLastTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
-                && mLastRegistrationStats != null) {
+                && mLastRegistrationState != REGISTRATION_STATE_NOT_REGISTERED) {
             mLastRegistrationStats.rat =
                     ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_PS);
         }
@@ -370,7 +378,7 @@
      */
     @NetworkType
     public synchronized int getImsVoiceRadioTech() {
-        if (mLastRegistrationStats == null
+        if (mLastRegistrationState == REGISTRATION_STATE_NOT_REGISTERED
                 || !mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE)) {
             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
@@ -404,11 +412,16 @@
     private ImsRegistrationStats getDefaultImsRegistrationStats() {
         Phone phone = mPhone.getDefaultPhone();
         ImsRegistrationStats stats = new ImsRegistrationStats();
-        stats.carrierId = phone.getCarrierId();
-        stats.simSlotIndex = phone.getPhoneId();
+        stats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         return stats;
     }
 
+    private void updateImsRegistrationStats() {
+        Phone phone = mPhone.getDefaultPhone();
+        mLastRegistrationStats.carrierId = phone.getCarrierId();
+        mLastRegistrationStats.simSlotIndex = phone.getPhoneId();
+    }
+
     @Nullable
     private MmTelCapabilities getLastCapableFeaturesForTech(@ImsRegistrationTech int radioTech) {
         switch (radioTech) {
@@ -438,21 +451,12 @@
         }
     }
 
-    private static ImsRegistrationStats copyOf(ImsRegistrationStats source) {
+    private static ImsRegistrationStats copyOfDimensionsOnly(ImsRegistrationStats source) {
         ImsRegistrationStats dest = new ImsRegistrationStats();
 
         dest.carrierId = source.carrierId;
         dest.simSlotIndex = source.simSlotIndex;
         dest.rat = source.rat;
-        dest.registeredMillis = source.registeredMillis;
-        dest.voiceCapableMillis = source.voiceCapableMillis;
-        dest.voiceAvailableMillis = source.voiceAvailableMillis;
-        dest.smsCapableMillis = source.smsCapableMillis;
-        dest.smsAvailableMillis = source.smsAvailableMillis;
-        dest.videoCapableMillis = source.videoCapableMillis;
-        dest.videoAvailableMillis = source.videoAvailableMillis;
-        dest.utCapableMillis = source.utCapableMillis;
-        dest.utAvailableMillis = source.utAvailableMillis;
 
         return dest;
     }
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 1a53ee6..bd7ce2a 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -1077,7 +1077,9 @@
                 roundAndConvertMillisToSeconds(stats.videoCapableMillis),
                 roundAndConvertMillisToSeconds(stats.videoAvailableMillis),
                 roundAndConvertMillisToSeconds(stats.utCapableMillis),
-                roundAndConvertMillisToSeconds(stats.utAvailableMillis));
+                roundAndConvertMillisToSeconds(stats.utAvailableMillis),
+                roundAndConvertMillisToSeconds(stats.registeringMillis),
+                roundAndConvertMillisToSeconds(stats.unregisteredMillis));
     }
 
     private static StatsEvent buildStatsEvent(ImsRegistrationTermination termination) {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index d495ca2..1da0c46 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -407,6 +407,8 @@
             existingStats.videoAvailableMillis += stats.videoAvailableMillis;
             existingStats.utCapableMillis += stats.utCapableMillis;
             existingStats.utAvailableMillis += stats.utAvailableMillis;
+            existingStats.registeringMillis += stats.registeringMillis;
+            existingStats.unregisteredMillis += stats.unregisteredMillis;
             existingStats.lastUsedMillis = getWallTimeMillis();
         } else {
             stats.lastUsedMillis = getWallTimeMillis();
@@ -2279,6 +2281,10 @@
                     normalizeDurationTo24H(stats[i].utCapableMillis, intervalMillis);
             stats[i].utAvailableMillis =
                     normalizeDurationTo24H(stats[i].utAvailableMillis, intervalMillis);
+            stats[i].registeringMillis =
+                    normalizeDurationTo24H(stats[i].registeringMillis, intervalMillis);
+            stats[i].unregisteredMillis =
+                    normalizeDurationTo24H(stats[i].unregisteredMillis, intervalMillis);
         }
         return stats;
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
index 3cc6a8b..4fcf620 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
@@ -52,7 +52,7 @@
         super.setUp(getClass().getSimpleName());
         mBundle = mContextFixture.getCarrierConfigBundle();
         when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle);
-        mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper());
+        mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper(), mFeatureFlags);
         logd("DataConfigManagerTest -Setup!");
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
index f1ab894..a09994b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -150,6 +150,7 @@
     // Events
     private static final int EVENT_SIM_STATE_CHANGED = 9;
     private static final int EVENT_REEVALUATE_EXISTING_DATA_NETWORKS = 16;
+    private static final int EVENT_SERVICE_STATE_CHANGED = 17;
     private static final int EVENT_VOICE_CALL_ENDED = 18;
     private static final int EVENT_SUBSCRIPTION_OVERRIDE = 23;
 
@@ -612,7 +613,7 @@
         doReturn(ss).when(mSST).getServiceState();
         doReturn(ss).when(mPhone).getServiceState();
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
     }
 
@@ -3574,8 +3575,12 @@
 
     @Test
     public void testNonVoPStoVoPSImsSetup() throws Exception {
-        // Even allow lingering when NoVops, should have no effect on NoVops -> Vops
-        mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true);
+        doReturn(true).when(mFeatureFlags).allowMmtelInNonVops();
+        mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(true);
+        // Config that allows non-vops bring up when Roaming
+        mCarrierConfig.putIntArray(CarrierConfigManager.Ims
+                .KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY, new int[]
+                {CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING});
         carrierConfigChanged();
 
         // VOPS not supported
@@ -3595,6 +3600,30 @@
         processAllMessages();
         verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
+        // Verify bring up in Home is not allowed.
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+        processAllMessages();
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+        // Verify bring up in Roaming is allowed.
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING, dsri);
+        processAllMessages();
+        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
+                NetworkCapabilities.NET_CAPABILITY_MMTEL);
+
+        // Verify the roaming network survives network re-evaluation.
+        mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS)
+                .sendToTarget();
+        processAllMessages();
+
+        // Service state changed to Home, non-vops area is no longer allowed
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+        processAllMessages();
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
         // VoPS supported
         dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
@@ -4170,8 +4199,6 @@
 
     @Test
     public void testHandoverDataNetworkNonVops() throws Exception {
-        ServiceState ss = new ServiceState();
-
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -4179,36 +4206,13 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         mDataNetworkControllerUT.addNetworkRequest(
@@ -4237,8 +4241,6 @@
         mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true);
         carrierConfigChanged();
 
-        ServiceState ss = new ServiceState();
-
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -4246,36 +4248,13 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         mDataNetworkControllerUT.addNetworkRequest(
@@ -4301,8 +4280,6 @@
 
     @Test
     public void testNonMmtelImsHandoverDataNetworkNonVops() throws Exception {
-        ServiceState ss = new ServiceState();
-
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -4311,35 +4288,13 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         // Bring up the IMS network that does not require MMTEL
@@ -4347,7 +4302,7 @@
                 createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS));
         processAllMessages();
 
-        // Even though the network request does not have MMTEL, but the network support it, so
+        // Even though the network request does not have MMTEL, the WLAN network support it, so
         // the network capabilities should still have MMTEL.
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
                 NetworkCapabilities.NET_CAPABILITY_MMTEL);
@@ -4361,9 +4316,9 @@
                 any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(),
                 any(), any(), anyBoolean(), any(Message.class));
 
-        // The IMS network should still have IMS and MMTEL.
+        // The IMS network should still have IMS, but MMTEL is removed.
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS);
-        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMTEL);
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
     }
 
     @Test
@@ -4372,8 +4327,6 @@
         mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true);
         carrierConfigChanged();
 
-        ServiceState ss = new ServiceState();
-
         // VoPS network
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
@@ -4383,35 +4336,13 @@
                         LteVopsSupportInfo.LTE_STATUS_SUPPORTED))
                 .build();
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         // Bring up the IMS network that does require MMTEL
@@ -4424,7 +4355,6 @@
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
                 NetworkCapabilities.NET_CAPABILITY_MMTEL);
 
-        ss = new ServiceState();
         // Non VoPS network
         dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
@@ -4434,32 +4364,10 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
-
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         // The IMS network is alive due to KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL = true
@@ -4663,7 +4571,7 @@
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
                 NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null);
         doReturn(ss).when(mSST).getServiceState();
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         mDataNetworkControllerUT.removeNetworkRequest(request);
         mDataNetworkControllerUT.addNetworkRequest(request);
         processAllMessages();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
index e34d1ba..a75a699 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
@@ -96,7 +96,6 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Executor;
-
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class DataNetworkTest extends TelephonyTest {
@@ -428,8 +427,8 @@
         setSuccessfulSetupDataResponse(
                 mMockedWwanDataServiceManager, 123, Collections.emptyList(), mDefaultQos);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -537,8 +536,8 @@
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -633,8 +632,8 @@
                 .build(), mPhone));
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         processAllMessages();
@@ -652,20 +651,7 @@
 
     @Test
     public void testCreateImsDataNetwork() throws Exception {
-        NetworkRequestList networkRequestList = new NetworkRequestList();
-        networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                .build(), mPhone));
-
-        setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
-
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mImsDataProfile, networkRequestList,
-                AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                DataAllowedReason.NORMAL, mDataNetworkCallback);
-        replaceInstance(DataNetwork.class, "mDataCallSessionStats",
-                mDataNetworkUT, mDataCallSessionStats);
-        processAllMessages();
+        createImsDataNetwork(true/*isMmtel*/);
 
         ArgumentCaptor<LinkProperties> linkPropertiesCaptor =
                 ArgumentCaptor.forClass(LinkProperties.class);
@@ -686,7 +672,7 @@
                 eq(DataCallResponse.PDU_SESSION_ID_NOT_SET), nullable(NetworkSliceInfo.class),
                 any(TrafficDescriptor.class), eq(true), any(Message.class));
         assertThat(mDataNetworkUT.getId()).isEqualTo(123);
-        assertThat(networkRequestList.get(0).getState())
+        assertThat(mDataNetworkUT.getAttachedNetworkRequestList().get(0).getState())
                 .isEqualTo(TelephonyNetworkRequest.REQUEST_STATE_SATISFIED);
         LinkProperties lp = mDataNetworkUT.getLinkProperties();
         assertThat(lp.getAddresses()).containsExactly(
@@ -742,8 +728,8 @@
         );
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mEnterpriseDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mEnterpriseDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -776,8 +762,8 @@
         );
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mUrlccDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mUrlccDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -809,8 +795,8 @@
         );
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mEmbbDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mEmbbDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -843,8 +829,8 @@
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mCbsDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mCbsDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -875,8 +861,8 @@
                         .getBytes())
         );
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mCbsDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mCbsDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -957,9 +943,10 @@
 
         setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mImsDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
-                DataAllowedReason.NORMAL, mDataNetworkCallback);
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mImsDataProfile, networkRequestList,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN, DataAllowedReason.NORMAL,
+                mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
                 mDataNetworkUT, mDataCallSessionStats);
         processAllMessages();
@@ -1179,8 +1166,8 @@
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1278,8 +1265,8 @@
         doReturn(false).when(mDataSettingsManager).isDataEnabled();
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.RESTRICTED_REQUEST, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1321,8 +1308,8 @@
         doReturn(false).when(mDataSettingsManager).isDataRoamingEnabled();
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.RESTRICTED_REQUEST, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1428,7 +1415,7 @@
 
     @Test
     public void testNetworkAgentConfig() throws Exception {
-        testCreateImsDataNetwork();
+        createImsDataNetwork(false/*IsMmtel*/);
 
         ArgumentCaptor<NetworkAgentConfig> captor = ArgumentCaptor
                 .forClass(NetworkAgentConfig.class);
@@ -1454,8 +1441,8 @@
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build(), mPhone));
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         NetworkCapabilities caps = mDataNetworkUT.getNetworkCapabilities();
@@ -1547,7 +1534,8 @@
     }
 
     @Test
-    public void testMovingToNonVops() throws Exception {
+    public void testMovingToNonVopsRequestedMmtel() throws Exception {
+        createImsDataNetwork(true/*isMmtel*/);
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -1557,7 +1545,6 @@
                 .build();
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
-        testCreateImsDataNetwork();
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue();
@@ -1578,6 +1565,37 @@
     }
 
     @Test
+    public void testNonMmtelImsMovingToNonVops() throws Exception {
+        createImsDataNetwork(false/*isMmtel*/);
+        DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
+                .setNrAvailable(true)
+                .setEnDcAvailable(true)
+                .setVopsSupportInfo(new LteVopsSupportInfo(
+                        LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
+                        LteVopsSupportInfo.LTE_STATUS_SUPPORTED))
+                .build();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+
+        assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue();
+
+        dsri = new DataSpecificRegistrationInfo.Builder(8)
+                .setNrAvailable(true)
+                .setEnDcAvailable(true)
+                .setVopsSupportInfo(new LteVopsSupportInfo(
+                        LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
+                        LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
+                .build();
+        logd("Trigger non VoPS");
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+        // MMTEL should be removed to reflect the actual Vops status.
+        assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_MMTEL)).isFalse();
+    }
+
+    @Test
     public void testCssIndicatorChanged() throws Exception {
         setupDataNetwork();
 
@@ -1808,8 +1826,8 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build(), mPhone));
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1951,8 +1969,8 @@
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build(), mPhone));
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                m5gDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, m5gDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1998,4 +2016,22 @@
         verify(mDataNetworkCallback).onLinkStatusChanged(eq(mDataNetworkUT),
                 eq(DataCallResponse.LINK_STATUS_INACTIVE));
     }
+
+    private void createImsDataNetwork(boolean isMmtel) throws Exception {
+        NetworkRequestList networkRequestList = new NetworkRequestList();
+        NetworkRequest.Builder builder = new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+        if (isMmtel) builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
+        networkRequestList.add(new TelephonyNetworkRequest(builder.build(), mPhone));
+
+        setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
+
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mImsDataProfile, networkRequestList,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                DataAllowedReason.NORMAL, mDataNetworkCallback);
+        replaceInstance(DataNetwork.class, "mDataCallSessionStats",
+                mDataNetworkUT, mDataCallSessionStats);
+        processAllMessages();
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
index 504782b..7c7c5b2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
@@ -308,12 +308,73 @@
         mImsStats.onImsCapabilitiesChanged(
                 REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL));
 
+        mImsStats.onImsUnregistered(
+                new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
+
         mImsStats.incTimeMillis(2000L);
         mImsStats.conclude();
 
-        // No atom should be generated
+        ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationTermination.class);
+        verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+        ImsRegistrationTermination termination = terminationCaptor.getValue();
+        assertEquals(CARRIER1_ID, termination.carrierId);
+        assertFalse(termination.isMultiSim);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
+        assertTrue(termination.setupFailed);
+        assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
+        assertEquals(999, termination.extraCode);
+        assertEquals("Timeout", termination.extraMessage);
+
+        // Registering duration should be counted
+        ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+        ImsRegistrationStats stats = statsCaptor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, stats.rat);
+        assertEquals(2000L, stats.unregisteredMillis);
+        verifyNoMoreInteractions(mPersistAtomsStorage);
+    }
+
+    @Test
+    @SmallTest
+    public void conclude_registering() throws Exception {
+        // IMS over LTE
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_VOICE,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_VIDEO,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_UT,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_SMS,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onImsCapabilitiesChanged(
+                REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL));
+
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WLAN);
+
+        mImsStats.incTimeMillis(2000L);
+        mImsStats.conclude();
+
+        // Registering duration should be counted
         ArgumentCaptor<ImsRegistrationStats> captor =
                 ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture());
+        ImsRegistrationStats stats = captor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.rat);
+        assertEquals(2000L, stats.registeringMillis);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -510,6 +571,57 @@
 
     @Test
     @SmallTest
+    public void onImsRegistered_afterImsRegistering() throws Exception {
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN);
+        mImsStats.incTimeMillis(2000L);
+        mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+
+        // Registering duration should be counted
+        ArgumentCaptor<ImsRegistrationStats> captor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture());
+        ImsRegistrationStats stats = captor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat);
+        assertEquals(0L, stats.registeredMillis);
+        assertEquals(2000L, stats.registeringMillis);
+    }
+
+    @Test
+    @SmallTest
+    public void onImsRegistering_afterImsUnregistered() throws Exception {
+        mImsStats.onImsUnregistered(
+                new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
+        mImsStats.incTimeMillis(2000L);
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN);
+
+        // Atom with termination info should be generated
+        ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationTermination.class);
+        verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+        ImsRegistrationTermination termination = terminationCaptor.getValue();
+        assertEquals(CARRIER1_ID, termination.carrierId);
+        assertFalse(termination.isMultiSim);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
+        assertTrue(termination.setupFailed);
+        assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
+        assertEquals(999, termination.extraCode);
+        assertEquals("Timeout", termination.extraMessage);
+
+        ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+        ImsRegistrationStats stats = statsCaptor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, stats.rat);
+        assertEquals(2000L, stats.unregisteredMillis);
+        verifyNoMoreInteractions(mPersistAtomsStorage);
+    }
+
+    @Test
+    @SmallTest
     public void onImsUnregistered_setupFailure() throws Exception {
         mImsStats.onImsUnregistered(
                 new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
@@ -521,7 +633,7 @@
         ImsRegistrationTermination termination = captor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
-        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
         assertTrue(termination.setupFailed);
         assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
         assertEquals(999, termination.extraCode);
@@ -532,16 +644,26 @@
     @Test
     @SmallTest
     public void onImsUnregistered_setupFailureWithProgress() throws Exception {
-        mImsStats.onImsRegistering(REGISTRATION_TECH_LTE);
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN);
         mImsStats.incTimeMillis(2000L);
         mImsStats.onImsUnregistered(
                 new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
 
         // Atom with termination info should be generated
-        ArgumentCaptor<ImsRegistrationTermination> captor =
+        ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+        ImsRegistrationStats stats = statsCaptor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat);
+        assertEquals(0L, stats.registeredMillis);
+        assertEquals(2000L, stats.registeringMillis);
+
+        ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
                 ArgumentCaptor.forClass(ImsRegistrationTermination.class);
-        verify(mPersistAtomsStorage).addImsRegistrationTermination(captor.capture());
-        ImsRegistrationTermination termination = captor.getValue();
+        verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+        ImsRegistrationTermination termination = terminationCaptor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
@@ -604,7 +726,7 @@
         ImsRegistrationTermination termination = captor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
-        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
         assertTrue(termination.setupFailed);
         assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
         assertEquals(0, termination.extraCode);
@@ -630,7 +752,7 @@
         ImsRegistrationTermination termination = captor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
-        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
         assertTrue(termination.setupFailed);
         assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
         assertEquals(0, termination.extraCode);