[automerger skipped] [automerged blank] Import translations. DO NOT MERGE ANYWHERE 2p: d82596210d am: 19084309b2 -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telephony/+/16982731

Change-Id: I1c4cf150bdc0de315346515654e2a111f26ead2c
diff --git a/src/com/android/phone/CallForwardEditPreference.java b/src/com/android/phone/CallForwardEditPreference.java
index bf296f9..45121f7 100644
--- a/src/com/android/phone/CallForwardEditPreference.java
+++ b/src/com/android/phone/CallForwardEditPreference.java
@@ -58,6 +58,7 @@
             CarrierXmlParser.SsEntry.SSAction.UNKNOWN;
     private int mAction;
     private HashMap<String, String> mCfInfo;
+    private long mDelayMillisAfterUssdSet = 1000;
 
     public CallForwardEditPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -488,8 +489,9 @@
                 mPhone.getCallForwardingOption(reason, mServiceClass,
                         obtainMessage(MESSAGE_GET_CF, msg.arg1, MESSAGE_SET_CF, ar.exception));
             } else {
-                mHandler.sendMessage(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
-                        msg.arg1, MyHandler.MESSAGE_SET_CF, ar.exception));
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
+                        msg.arg1, MyHandler.MESSAGE_SET_CF, ar.exception),
+                        mDelayMillisAfterUssdSet);
             }
         }
 
diff --git a/src/com/android/phone/CallWaitingSwitchPreference.java b/src/com/android/phone/CallWaitingSwitchPreference.java
index 01dd3b2..609488c 100644
--- a/src/com/android/phone/CallWaitingSwitchPreference.java
+++ b/src/com/android/phone/CallWaitingSwitchPreference.java
@@ -6,28 +6,34 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.preference.SwitchPreference;
+import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
 
-import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 public class CallWaitingSwitchPreference extends SwitchPreference {
     private static final String LOG_TAG = "CallWaitingSwitchPreference";
+    private static final int DELAY_MILLIS_FOR_USSD = 1000;
     private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private final MyHandler mHandler = new MyHandler();
     private Phone mPhone;
     private TimeConsumingPreferenceListener mTcpListener;
-    private Executor mExecutor;
+    private ScheduledExecutorService mExecutor;
     private TelephonyManager mTelephonyManager;
     private boolean mIsDuringUpdateProcess = false;
     private int mUpdateStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR;
     private int mQueryStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR;
+    private boolean mUssdMode = false;
 
     public CallWaitingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
@@ -45,9 +51,14 @@
             TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) {
         mPhone = phone;
         mTcpListener = listener;
-        mExecutor = Executors.newSingleThreadExecutor();
+        mExecutor = Executors.newSingleThreadScheduledExecutor();
         mTelephonyManager = getContext().getSystemService(
                 TelephonyManager.class).createForSubscriptionId(phone.getSubId());
+        CarrierConfigManager configManager = getContext().getSystemService(
+                CarrierConfigManager.class);
+        PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId());
+        mUssdMode = (bundle != null) ? bundle.getBoolean(
+                CarrierConfigManager.KEY_USE_CALL_WAITING_USSD_BOOL, false) : false;
 
         if (!skipReading) {
             Log.d(LOG_TAG, "init getCallWaitingStatus");
@@ -67,7 +78,23 @@
     private void updateStatusCallBack(int result) {
         Log.d(LOG_TAG, "updateStatusCallBack: CW state " + result + ", and re get");
         mUpdateStatus = result;
-        mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack);
+        if (mUssdMode) {
+            Log.d(LOG_TAG, "updateStatusCallBack: USSD mode needs to wait 1s since Framework"
+                    + " has the limitation");
+            Consumer<Integer> resultListener = this::queryStatusCallBack;
+            try {
+                mExecutor.schedule(new Runnable() {
+                    @Override
+                    public void run() {
+                        mTelephonyManager.getCallWaitingStatus(mExecutor, resultListener);
+                    }
+                }, DELAY_MILLIS_FOR_USSD, TimeUnit.MILLISECONDS);
+            } catch (Exception e) {
+                Log.d(LOG_TAG, "Exception while waiting: " + e);
+            }
+        } else {
+            mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack);
+        }
     }
 
     @Override
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index a463243..45ca974 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -65,6 +65,7 @@
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -1064,6 +1065,7 @@
         }
 
         String fileName;
+        String iccid = null;
         if (isNoSimConfig) {
             fileName = getFilenameForNoSimConfig(packageName);
         } else {
@@ -1073,7 +1075,7 @@
                 return null;
             }
 
-            final String iccid = getIccIdForPhoneId(phoneId);
+            iccid = getIccIdForPhoneId(phoneId);
             final int cid = getSpecificCarrierIdForPhoneId(phoneId);
             if (iccid == null) {
                 loge("Cannot restore config with null iccid.");
@@ -1102,7 +1104,15 @@
         } catch (FileNotFoundException e) {
             // Missing file is normal occurrence that might occur with a new sim or when restoring
             // an override file during boot and should not be treated as an error.
-            if (file != null) logd("File not found: " + file.getPath());
+            if (file != null) {
+                if (isNoSimConfig) {
+                    logd("File not found: " + file.getPath());
+                } else {
+                    String filePath = file.getPath();
+                    filePath = getFilePathForLogging(filePath, iccid);
+                    logd("File not found : " + filePath);
+                }
+            }
         } catch (IOException e) {
             loge(e.toString());
         }
@@ -1110,6 +1120,22 @@
         return restoredBundle;
     }
 
+    /**
+     * This method will mask most part of iccid in the filepath for logging on userbuild
+     */
+    private String getFilePathForLogging(String filePath, String iccid) {
+        // If loggable then return with actual file path
+        if (Rlog.isLoggable(LOG_TAG, Log.VERBOSE)) {
+            return filePath;
+        }
+        String path = filePath;
+        int length = (iccid != null) ? iccid.length() : 0;
+        if (length > 5 && filePath != null) {
+            path = filePath.replace(iccid.substring(5), "***************");
+        }
+        return path;
+    }
+
     private PersistableBundle restoreConfigFromXml(String packageName, @NonNull String extraString,
             int phoneId) {
         return restoreConfigFromXml(packageName, extraString, phoneId, false);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 03b0be9..d96c0c5 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -22,6 +22,7 @@
 import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_GSM;
 import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_IMS;
 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__CLIENT_PARAMS_SENT;
 
 import android.Manifest;
 import android.Manifest.permission;
@@ -180,6 +181,7 @@
 import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
+import com.android.internal.telephony.metrics.RcsStats;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.uicc.IccIoResult;
@@ -2055,7 +2057,8 @@
                 case CMD_PREPARE_UNATTENDED_REBOOT:
                     request = (MainThreadRequest) msg.obj;
                     request.result =
-                            UiccController.getInstance().getPinStorage().prepareUnattendedReboot();
+                            UiccController.getInstance().getPinStorage()
+                                .prepareUnattendedReboot(request.workSource);
                     notifyRequester(request);
                     break;
 
@@ -5511,11 +5514,9 @@
      */
     public int setForbiddenPlmns(int subId, int appType, List<String> fplmns, String callingPackage,
             String callingFeatureId) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
-                callingFeatureId, "setForbiddenPlmns")) {
-            if (DBG) logv("no permissions for setForbiddenplmns");
-            throw new IllegalStateException("No Permissions for setForbiddenPlmns");
-        }
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                mApp, subId, "setForbiddenPlmns");
+
         if (appType != TelephonyManager.APPTYPE_USIM && appType != TelephonyManager.APPTYPE_SIM) {
             loge("setForbiddenPlmnList(): App Type must be USIM or SIM");
             throw new IllegalArgumentException("Invalid appType: App Type must be USIM or SIM");
@@ -6921,7 +6922,9 @@
                 for (int p = packages.size() - 1; p >= 0; p--) {
                     PackageInfo pkgInfo = packages.get(p);
                     if (pkgInfo != null && pkgInfo.packageName != null
-                            && card.getCarrierPrivilegeStatus(pkgInfo)
+                            && getCarrierPrivilegeStatusFromCarrierConfigRules(
+                                    card.getCarrierPrivilegeStatus(pkgInfo),
+                                    getPhone(phoneId), pkgInfo.packageName)
                             == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                         privilegedPackages.add(pkgInfo.packageName);
                     }
@@ -8321,6 +8324,16 @@
             int result = (int) sendRequest(CMD_ENABLE_VONR, enabled, subId,
                     workSource);
             if (DBG) log("setVoNrEnabled result: " + result);
+
+            if (result == TelephonyManager.ENABLE_VONR_SUCCESS) {
+                if (DBG) {
+                    log("Set VoNR settings in siminfo db; subId=" + subId + ", value:" + enabled);
+                }
+                SubscriptionManager.setSubscriptionProperty(
+                        subId, SubscriptionManager.NR_ADVANCED_CALLING_ENABLED,
+                        (enabled ? "1" : "0"));
+            }
+
             return result;
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -10389,6 +10402,9 @@
             } else {
                 configBinder.setRcsClientConfiguration(rcc);
             }
+
+            RcsStats.getInstance().onRcsClientProvisioningStats(subId,
+                    RCS_CLIENT_PROVISIONING_STATS__EVENT__CLIENT_PARAMS_SENT);
         } catch (RemoteException e) {
             Rlog.e(LOG_TAG, "fail to setRcsClientConfiguration " + e.getMessage());
             throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
@@ -10894,11 +10910,12 @@
     @Override
     @TelephonyManager.PrepareUnattendedRebootResult
     public int prepareForUnattendedReboot() {
+        WorkSource workSource = getWorkSource(Binder.getCallingUid());
         enforceRebootPermission();
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            return (int) sendRequest(CMD_PREPARE_UNATTENDED_REBOOT, null);
+            return (int) sendRequest(CMD_PREPARE_UNATTENDED_REBOOT, null, workSource);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index 6d2bd6f..e819afc 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -16,6 +16,10 @@
 
 package com.android.phone;
 
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION;
+
 import android.Manifest;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.role.RoleManager;
@@ -47,6 +51,8 @@
 import com.android.ims.FeatureUpdates;
 import com.android.ims.RcsFeatureManager;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.metrics.RcsStats;
+import com.android.internal.telephony.metrics.RcsStats.RcsProvisioningCallback;
 import com.android.internal.telephony.util.HandlerExecutor;
 import com.android.internal.util.CollectionUtils;
 import com.android.telephony.Rlog;
@@ -100,6 +106,8 @@
     private final RoleManagerAdapter mRoleManager;
     private FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory;
 
+    private RcsStats mRcsStats;
+
     private static RcsProvisioningMonitor sInstance;
 
     private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener =
@@ -227,6 +235,10 @@
             if (mSingleRegistrationCapability != singleRegistrationCapability) {
                 mSingleRegistrationCapability = singleRegistrationCapability;
                 notifyDma();
+
+                // update whether single registration supported.
+                mRcsStats.setEnableSingleRegistration(mSubId,
+                        mSingleRegistrationCapability == ProvisioningManager.STATUS_CAPABLE);
             }
         }
 
@@ -338,6 +350,9 @@
                     } else {
                         notifyRcsAutoConfigurationReceived();
                     }
+
+                    // check callback for metrics if not registered, register callback
+                    registerMetricsCallback();
                 } else {
                     // clear callbacks if rcs disconnected
                     clearCallbacks();
@@ -397,6 +412,18 @@
                 }
             }
         }
+
+        private void registerMetricsCallback() {
+            RcsProvisioningCallback rcsProvisioningCallback = mRcsStats.getRcsProvisioningCallback(
+                    mSubId, mSingleRegistrationCapability == ProvisioningManager.STATUS_CAPABLE);
+
+            // if not yet registered, register callback and set registered value
+            if (rcsProvisioningCallback != null && !rcsProvisioningCallback.getRegistered()) {
+                if (addRcsConfigCallback(rcsProvisioningCallback)) {
+                    rcsProvisioningCallback.setRegistered(true);
+                }
+            }
+        }
     }
 
     @VisibleForTesting
@@ -454,7 +481,7 @@
 
     @VisibleForTesting
     public RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager,
-            FeatureConnectorFactory<RcsFeatureManager> factory) {
+            FeatureConnectorFactory<RcsFeatureManager> factory, RcsStats rcsStats) {
         mPhone = app;
         mHandler = new MyHandler(looper);
         mCarrierConfigManager = mPhone.getSystemService(CarrierConfigManager.class);
@@ -465,6 +492,7 @@
         logv("DMA is " + mDmaPackageName);
         mDmaChangedListener = new DmaChangedListener();
         mFeatureFactory = factory;
+        mRcsStats = rcsStats;
         init();
     }
 
@@ -477,7 +505,8 @@
             HandlerThread handlerThread = new HandlerThread(TAG);
             handlerThread.start();
             sInstance = new RcsProvisioningMonitor(app, handlerThread.getLooper(),
-                    new RoleManagerAdapterImpl(app), RcsFeatureManager::getConnector);
+                    new RoleManagerAdapterImpl(app), RcsFeatureManager::getConnector,
+                    RcsStats.getInstance());
         }
         return sInstance;
     }
@@ -704,6 +733,10 @@
                     logv("acs not used, set cached config and notify.");
                     v.setConfig(cachedConfig);
                 }
+
+                // store RCS metrics - DMA changed event
+                mRcsStats.onRcsClientProvisioningStats(k,
+                        RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED);
             });
         }
     }
@@ -803,6 +836,14 @@
         }
         info.setConfig(isCompressed ? RcsConfig.decompressGzip(config) : config);
         updateConfigForSub(subId, config, isCompressed);
+
+        // Supporting ACS means config data comes from ACS
+        // store RCS metrics - received provisioning event
+        if (isAcsUsed(subId)) {
+            mRcsStats.onRcsAcsProvisioningStats(subId, 200,
+                    RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML,
+                    isRcsVolteSingleRegistrationEnabled(subId));
+        }
     }
 
     private void onReconfigRequest(int subId) {
@@ -814,6 +855,10 @@
             updateConfigForSub(subId, null, true);
             info.triggerRcsReconfiguration();
         }
+
+        // store RCS metrics - reconfig event
+        mRcsStats.onRcsClientProvisioningStats(subId,
+                RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION);
     }
 
     private void notifyDmaForSub(int subId, int capability) {
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 7f088f7..c62b4fa 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -534,6 +534,10 @@
                 (properties & Connection.PROPERTY_IS_ADHOC_CONFERENCE) != 0);
         Log.i(this, "applyHostProperties: confProp=%s", conferenceProperties);
 
+        conferenceProperties = changeBitmask(conferenceProperties,
+                Connection.PROPERTY_CROSS_SIM,
+                (properties & Connection.PROPERTY_CROSS_SIM) != 0);
+
         return conferenceProperties;
     }
 
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 4f6acc8..8c5fb66 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -498,7 +498,8 @@
 
         IntentFilter intentFilter = new IntentFilter(
                 TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
-        registerReceiver(mTtyBroadcastReceiver, intentFilter);
+        registerReceiver(mTtyBroadcastReceiver, intentFilter,
+                android.Manifest.permission.MODIFY_PHONE_STATE, null);
     }
 
     @Override
diff --git a/src/com/android/services/telephony/rcs/DelegateStateTracker.java b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
index 321c7ba..18aab88 100644
--- a/src/com/android/services/telephony/rcs/DelegateStateTracker.java
+++ b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
@@ -24,9 +24,12 @@
 import android.telephony.ims.aidl.ISipDelegate;
 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
 import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
 
+import com.android.internal.telephony.metrics.RcsStats;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -50,11 +53,15 @@
     private boolean mCreatedCalled = false;
     private int mRegistrationStateOverride = -1;
 
+    private Set<String> mDelegateSupportedTags;
+    private final RcsStats mRcsStats;
+
     public DelegateStateTracker(int subId, ISipDelegateConnectionStateCallback appStateCallback,
-            ISipDelegate localDelegateImpl) {
+            ISipDelegate localDelegateImpl, RcsStats rcsStats) {
         mSubId = subId;
         mAppStateCallback = appStateCallback;
         mLocalDelegateImpl = localDelegateImpl;
+        mRcsStats = rcsStats;
     }
 
     /**
@@ -63,10 +70,13 @@
      * Registration and state updates will be send via the
      * {@link SipDelegateBinderConnection.StateCallback} callback implemented by this class as they
      * arrive.
+     * @param supportedTags the tags supported by the SipTransportController and ImsService creating
+     *                      the SipDelegate. These tags will be used as a key for SipDelegate
+     *                      metrics.
      * @param deniedTags The tags denied by the SipTransportController and ImsService creating the
      *         SipDelegate. These tags will need to be notified back to the IMS application.
      */
-    public void sipDelegateConnected(Set<FeatureTagState> deniedTags) {
+    public void sipDelegateConnected(Set<String> supportedTags, Set<FeatureTagState> deniedTags) {
         logi("SipDelegate connected with denied tags:" + deniedTags);
         // From the IMS application perspective, we only call onCreated/onDestroyed once and
         // provide the local implementation of ISipDelegate, which doesn't change, even though
@@ -74,6 +84,8 @@
         if (!mCreatedCalled) {
             mCreatedCalled = true;
             notifySipDelegateCreated();
+            mDelegateSupportedTags = supportedTags;
+            mRcsStats.createSipDelegateStats(mSubId, mDelegateSupportedTags);
         }
         mRegistrationStateOverride = -1;
         mDelegateDeniedTags = new ArrayList<>(deniedTags);
@@ -84,8 +96,8 @@
      *
      * This will trigger an override of the IMS application's registration state. All feature tags
      * in the REGISTERED state will be overridden to move to the deregistering state specified until
-     * a new SipDelegate was successfully created and {@link #sipDelegateConnected(Set)} was called
-     * or it was destroyed and {@link #sipDelegateDestroyed(int)} was called.
+     * a new SipDelegate was successfully created and {@link #sipDelegateConnected(Set, Set)} was
+     * called or it was destroyed and {@link #sipDelegateDestroyed(int)} was called.
      * @param deregisteringReason The new deregistering reason that all feature tags in the
      *         registered state should now report.
      */
@@ -115,6 +127,7 @@
         mRegistrationStateOverride = -1;
         try {
             mAppStateCallback.onDestroyed(reason);
+            mRcsStats.onSipDelegateStats(mSubId, mDelegateSupportedTags, reason);
         } catch (RemoteException e) {
             logw("sipDelegateDestroyed: IMS application is dead: " + e);
         }
@@ -141,6 +154,11 @@
         logi("onRegistrationStateChanged: sending reg state " + registrationState);
         try {
             mAppStateCallback.onFeatureTagStatusChanged(registrationState, mDelegateDeniedTags);
+            Set<String> registeredFeatureTags = registrationState.getRegisteredFeatureTags();
+            mRcsStats.onSipTransportFeatureTagStats(mSubId,
+                    new ArraySet<FeatureTagState>(mDelegateDeniedTags),
+                    registrationState.getDeregisteredFeatureTags(),
+                    registeredFeatureTags);
         } catch (RemoteException e) {
             logw("onRegistrationStateChanged: IMS application is dead: " + e);
         }
diff --git a/src/com/android/services/telephony/rcs/SipDelegateController.java b/src/com/android/services/telephony/rcs/SipDelegateController.java
index 8cc70a4..c728141 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateController.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateController.java
@@ -34,6 +34,7 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.metrics.RcsStats;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
@@ -102,7 +103,7 @@
         mMessageTransportWrapper = new MessageTransportWrapper(mSubId, executorService,
                 messageCallback);
         mDelegateStateTracker = new DelegateStateTracker(mSubId, stateCallback,
-                mMessageTransportWrapper.getDelegateConnection());
+                mMessageTransportWrapper.getDelegateConnection(), RcsStats.getInstance());
     }
 
     /**
@@ -191,7 +192,7 @@
                     .collect(Collectors.toSet()));
             mMessageTransportWrapper.openTransport(resultPair.first, allowedTags,
                     resultPair.second);
-            mDelegateStateTracker.sipDelegateConnected(resultPair.second);
+            mDelegateStateTracker.sipDelegateConnected(allowedTags, resultPair.second);
             return true;
         });
     }
diff --git a/src/com/android/services/telephony/rcs/SipSessionTracker.java b/src/com/android/services/telephony/rcs/SipSessionTracker.java
index 5ab482f..68e3065 100644
--- a/src/com/android/services/telephony/rcs/SipSessionTracker.java
+++ b/src/com/android/services/telephony/rcs/SipSessionTracker.java
@@ -24,6 +24,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.SipMessageParsingUtils;
+import com.android.internal.telephony.metrics.RcsStats;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
@@ -66,6 +67,14 @@
     // associated pending operation.
     private final ArrayMap<String, Runnable> mPendingAck = new ArrayMap<>();
 
+    private final RcsStats mRcsStats;
+    int mSubId;
+
+    public SipSessionTracker(int subId, RcsStats rcsStats) {
+        mSubId = subId;
+        mRcsStats = rcsStats;
+    }
+
     /**
      * Filter a SIP message to determine if it will result in a new SIP dialog. This will need to be
      * successfully acknowledged by the remote IMS stack using
@@ -73,10 +82,10 @@
      *
      * @param message The Incoming SIP message.
      */
-    public void filterSipMessage(SipMessage message) {
+    public void filterSipMessage(int direction, SipMessage message) {
         final Runnable r;
         if (startsEarlyDialog(message)) {
-            r = getCreateDialogRunnable(message);
+            r = getCreateDialogRunnable(direction, message);
         } else if (closesDialog(message)) {
             r = getCloseDialogRunnable(message);
         } else if (SipMessageParsingUtils.isSipResponse(message.getStartLine())) {
@@ -137,6 +146,8 @@
         if (dialogsToCleanup.isEmpty()) return;
         logi("Cleanup dialogs associated with call id: " + callId);
         for (SipDialog d : dialogsToCleanup) {
+            mRcsStats.onSipTransportSessionClosed(mSubId, callId, 0,
+                    d.getState() == d.STATE_CLOSED);
             d.close();
             logi("Dialog closed: " + d);
         }
@@ -197,6 +208,9 @@
      * Clears all tracked sessions.
      */
     public void clearAllSessions() {
+        for (SipDialog d : mTrackedDialogs) {
+            mRcsStats.onSipTransportSessionClosed(mSubId, d.getCallId(), 0, false);
+        }
         mTrackedDialogs.clear();
         mPendingAck.clear();
     }
@@ -262,7 +276,7 @@
         return SIP_CLOSE_DIALOG_REQUEST_METHOD.equalsIgnoreCase(startLineSegments[0]);
     }
 
-    private Runnable getCreateDialogRunnable(SipMessage m) {
+    private Runnable getCreateDialogRunnable(int direction, SipMessage m) {
         return () -> {
             List<SipDialog> duplicateDialogs = mTrackedDialogs.stream()
                     .filter(d -> d.getCallId().equals(m.getCallIdParameter()))
@@ -273,6 +287,10 @@
                 return;
             }
             SipDialog dialog = SipDialog.fromSipMessage(m);
+            String[] startLineSegments =
+                    SipMessageParsingUtils.splitStartLineAndVerify(m.getStartLine());
+            mRcsStats.earlySipTransportSession(startLineSegments[0], dialog.getCallId(),
+                    direction);
             logi("Starting new SipDialog: " + dialog);
             mTrackedDialogs.add(dialog);
         };
@@ -285,6 +303,7 @@
                     .collect(Collectors.toList());
             if (dialogsToClose.isEmpty()) return;
             logi("Closing dialogs associated with: " + m);
+            mRcsStats.onSipTransportSessionClosed(mSubId, m.getCallIdParameter(), 0, true);
             for (SipDialog d : dialogsToClose) {
                 d.close();
                 logi("Dialog closed: " + d);
@@ -344,11 +363,13 @@
         if (statusCode <= 100) return;
         // If 300+, then this dialog has received an error response and should move to closed state.
         if (statusCode >= 300) {
+            mRcsStats.onSipTransportSessionClosed(mSubId, m.getCallIdParameter(), statusCode, true);
             d.close();
             return;
         }
         if (toTag == null) logw("updateSipDialogState: No to tag for message: " + m);
         if (statusCode >= 200) {
+            mRcsStats.confirmedSipTransportSession(m.getCallIdParameter(), statusCode);
             d.confirm(toTag);
             return;
         }
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index 034382c..046910c 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.telephony.metrics.RcsStats;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.phone.R;
 
@@ -163,6 +164,7 @@
         mFeatureControllers = new SparseArray<>(numSlots);
         mSlotToAssociatedSubIds = new SparseArray<>(numSlots);
         mRcsUceEnabled = sResourceProxy.getDeviceUceEnabled(mContext);
+        RcsStats.getInstance().registerUceCallback();
     }
 
     @VisibleForTesting
@@ -173,6 +175,7 @@
         mSlotToAssociatedSubIds = new SparseArray<>(numSlots);
         sResourceProxy = resourceProxy;
         mRcsUceEnabled = sResourceProxy.getDeviceUceEnabled(mContext);
+        RcsStats.getInstance().registerUceCallback();
     }
 
     /**
diff --git a/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
index 777026c..3b1b26d 100644
--- a/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
+++ b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
@@ -16,6 +16,9 @@
 
 package com.android.services.telephony.rcs;
 
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING;
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING;
+
 import android.telephony.ims.DelegateRegistrationState;
 import android.telephony.ims.FeatureTagState;
 import android.telephony.ims.SipDelegateConfiguration;
@@ -26,6 +29,8 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.SipMessageParsingUtils;
+import com.android.internal.telephony.metrics.RcsStats;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.services.telephony.rcs.validator.IncomingTransportStateValidator;
 import com.android.services.telephony.rcs.validator.MalformedSipMessageValidator;
@@ -145,11 +150,13 @@
     private PendingTask mPendingClose;
     private PendingRegCleanupTask mPendingRegCleanup;
     private Consumer<Set<String>> mRegistrationAppliedConsumer;
+    private final RcsStats mRcsStats;
 
     public TransportSipMessageValidator(int subId, ScheduledExecutorService executor) {
         mSubId = subId;
         mExecutor = executor;
-        mSipSessionTracker = new SipSessionTracker();
+        mRcsStats = RcsStats.getInstance();
+        mSipSessionTracker = new SipSessionTracker(subId, mRcsStats);
         mOutgoingTransportStateValidator = new OutgoingTransportStateValidator(mSipSessionTracker);
         mIncomingTransportStateValidator = new IncomingTransportStateValidator();
         mOutgoingMessageValidator = new MalformedSipMessageValidator().andThen(
@@ -163,7 +170,7 @@
     public TransportSipMessageValidator(int subId, ScheduledExecutorService executor,
             SipSessionTracker sipSessionTracker,
             OutgoingTransportStateValidator outgoingStateValidator,
-            IncomingTransportStateValidator incomingStateValidator) {
+            IncomingTransportStateValidator incomingStateValidator, RcsStats rcsStats) {
         mSubId = subId;
         mExecutor = executor;
         mSipSessionTracker = sipSessionTracker;
@@ -171,6 +178,7 @@
         mIncomingTransportStateValidator = incomingStateValidator;
         mOutgoingMessageValidator = mOutgoingTransportStateValidator;
         mIncomingMessageValidator = mIncomingTransportStateValidator;
+        mRcsStats = rcsStats;
     }
 
     /**
@@ -365,7 +373,11 @@
         }
         ValidationResult result = mOutgoingMessageValidator.validate(message);
         logi("verifyOutgoingMessage: " + result + ", message=" + message);
-        if (result.isValidated) mSipSessionTracker.filterSipMessage(message);
+        if (result.isValidated) {
+            mSipSessionTracker.filterSipMessage(
+                    SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, message);
+        }
+        updateForMetrics(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, message, result);
         return result;
     }
 
@@ -378,7 +390,11 @@
     public ValidationResult verifyIncomingMessage(SipMessage message) {
         ValidationResult result = mIncomingMessageValidator.validate(message);
         logi("verifyIncomingMessage: " + result + ", message=" + message);
-        if (result.isValidated) mSipSessionTracker.filterSipMessage(message);
+        if (result.isValidated) {
+            mSipSessionTracker.filterSipMessage(
+                    SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, message);
+        }
+        updateForMetrics(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, message, result);
         return result;
     }
 
@@ -539,6 +555,28 @@
                 .collect(Collectors.toSet());
     }
 
+    private void updateForMetrics(int direction, SipMessage m, ValidationResult result) {
+        String[] startLineSegments = SipMessageParsingUtils
+                .splitStartLineAndVerify(m.getStartLine());
+        if (SipMessageParsingUtils.isSipRequest(m.getStartLine())) {
+            if (result.isValidated) {
+                // SipMessage add to list for Metrics stats
+                mRcsStats.onSipMessageRequest(m.getCallIdParameter(), startLineSegments[0],
+                        direction);
+            } else {
+                //Message sending fail and there is no response.
+                mRcsStats.invalidatedMessageResult(mSubId, startLineSegments[0], direction,
+                        result.restrictedReason);
+            }
+        } else if (SipMessageParsingUtils.isSipResponse(m.getStartLine())) {
+            int statusCode = Integer.parseInt(startLineSegments[1]);
+            mRcsStats.onSipMessageResponse(mSubId, m.getCallIdParameter(), statusCode,
+                    result.restrictedReason);
+        } else {
+            logw("Message is Restricted");
+        }
+    }
+
     private void logi(String log) {
         Log.i(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log);
         mLocalLog.log("[I] " + log);
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index 8e5e073..8873402 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -16,6 +16,10 @@
 
 package com.android.phone;
 
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
@@ -64,6 +68,7 @@
 import com.android.ims.FeatureConnector;
 import com.android.ims.RcsFeatureManager;
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.metrics.RcsStats;
 
 import org.junit.After;
 import org.junit.Before;
@@ -179,6 +184,10 @@
     private IRcsConfigCallback mCallback;
     @Mock
     private PackageManager mPackageManager;
+    @Mock
+    private RcsStats mRcsStats;
+    @Mock
+    private RcsStats.RcsProvisioningCallback mRcsProvisioningCallback;
 
     private Executor mExecutor = new Executor() {
         @Override
@@ -768,6 +777,66 @@
         assertNull(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
     }
 
+    @Test
+    @SmallTest
+    public void testMetricsAcsNotUsed() throws Exception {
+        createMonitor(1);
+
+        // Not used ACS
+        mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, false);
+        broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+        processAllMessages();
+        mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
+        processAllMessages();
+        verify(mRcsStats, never()).onRcsAcsProvisioningStats(anyInt(), anyInt(),
+                anyInt(), anyBoolean());
+    }
+
+    @Test
+    @SmallTest
+    public void testMetricsAcsUsed() throws Exception {
+        when(mRcsStats.getRcsProvisioningCallback(anyInt(), anyBoolean()))
+                .thenReturn(mRcsProvisioningCallback);
+        createMonitor(1);
+
+        verify(mIImsConfig, times(1))
+                .notifyRcsAutoConfigurationReceived(any(), anyBoolean());
+        // verify RcsStats.getRcsProvisioningCallback() is called
+        verify(mRcsStats, times(1)).getRcsProvisioningCallback(
+                eq(FAKE_SUB_ID_BASE), anyBoolean());
+        // verify registered callback obj which comes from RcsStats.getRcsProvisioningCallback()
+        verify(mIImsConfig, times(1))
+                .addRcsConfigCallback(eq(mRcsProvisioningCallback));
+
+        // Config data received and ACS used
+        int errorCode = 200;
+        mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, true);
+        broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+        processAllMessages();
+        mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
+        processAllMessages();
+        verify(mRcsStats, times(1)).onRcsAcsProvisioningStats(eq(FAKE_SUB_ID_BASE), eq(errorCode),
+                eq(RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML), anyBoolean());
+    }
+
+    @Test
+    @SmallTest
+    public void testMetricsClientProvisioningStats() throws Exception {
+        createMonitor(1);
+
+        // reconfig trigger
+        mRcsProvisioningMonitor.requestReconfig(FAKE_SUB_ID_BASE);
+        processAllMessages();
+        verify(mRcsStats, times(1)).onRcsClientProvisioningStats(eq(FAKE_SUB_ID_BASE),
+                eq(RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION));
+
+        // DMA changed
+        updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
+        processAllMessages();
+        verify(mRcsStats, times(1)).onRcsClientProvisioningStats(eq(FAKE_SUB_ID_BASE),
+                eq(RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED));
+    }
+
     private void createMonitor(int subCount) throws Exception {
         if (Looper.myLooper() == null) {
             Looper.prepare();
@@ -777,7 +846,7 @@
                 .thenReturn(mFeatureConnector);
         when(mFeatureManager.getConfig()).thenReturn(mIImsConfig);
         mRcsProvisioningMonitor = new RcsProvisioningMonitor(mPhone, mHandlerThread.getLooper(),
-                mRoleManager, mFeatureFactory);
+                mRoleManager, mFeatureFactory, mRcsStats);
         mHandler = mRcsProvisioningMonitor.getHandler();
         try {
             mLooper = new TestableLooper(mHandler.getLooper());
diff --git a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
index 8236f44..25b5339 100644
--- a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
@@ -37,6 +37,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
+import com.android.internal.telephony.metrics.RcsStats;
 
 import org.junit.After;
 import org.junit.Before;
@@ -56,6 +57,7 @@
 
     @Mock private ISipDelegate mSipDelegate;
     @Mock private ISipDelegateConnectionStateCallback mAppCallback;
+    @Mock private RcsStats mRcsStats;
 
     @Before
     public void setUp() throws Exception {
@@ -76,12 +78,14 @@
     @Test
     public void testDelegateCreated() throws Exception {
         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
-                mSipDelegate);
+                mSipDelegate, mRcsStats);
         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
-        stateTracker.sipDelegateConnected(deniedTags);
+        Set<String> supportedTags = getSupportedTags();
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
         // Calling connected multiple times should not generate multiple onCreated events.
-        stateTracker.sipDelegateConnected(deniedTags);
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
         verify(mAppCallback).onCreated(mSipDelegate);
+        verify(mRcsStats).createSipDelegateStats(TEST_SUB_ID, supportedTags);
 
         // Ensure status updates are sent to app as expected.
         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -97,8 +101,10 @@
         stateTracker.onConfigurationChanged(c);
         verify(mAppCallback).onFeatureTagStatusChanged(eq(regState),
                 eq(new ArrayList<>(deniedTags)));
+        verify(mRcsStats).onSipTransportFeatureTagStats(TEST_SUB_ID, deniedTags,
+                regState.getDeregisteredFeatureTags(),
+                regState.getRegisteredFeatureTags());
         verify(mAppCallback).onConfigurationChanged(c);
-
         verify(mAppCallback, never()).onDestroyed(anyInt());
     }
 
@@ -109,14 +115,18 @@
     @Test
     public void testDelegateDestroyed() throws Exception {
         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
-                mSipDelegate);
+                mSipDelegate, mRcsStats);
         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
-        stateTracker.sipDelegateConnected(deniedTags);
+        Set<String> supportedTags = getSupportedTags();
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
+        verify(mRcsStats).createSipDelegateStats(eq(TEST_SUB_ID), eq(supportedTags));
 
         stateTracker.sipDelegateDestroyed(
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
         verify(mAppCallback).onDestroyed(
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+        verify(mRcsStats).onSipDelegateStats(eq(TEST_SUB_ID), eq(supportedTags),
+                eq(SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP));
     }
 
     /**
@@ -130,9 +140,10 @@
     @Test
     public void testDelegateChangingRegisteredTagsOverride() throws Exception {
         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
-                mSipDelegate);
+                mSipDelegate, mRcsStats);
         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
-        stateTracker.sipDelegateConnected(deniedTags);
+        Set<String> supportedTags = getSupportedTags();
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
         // SipDelegate created
         verify(mAppCallback).onCreated(mSipDelegate);
         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -158,7 +169,7 @@
                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
                 .build();
         // new underlying SipDelegate created
-        stateTracker.sipDelegateConnected(deniedTags);
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
         stateTracker.onRegistrationStateChanged(regState);
 
         // Verify registration state through the process:
@@ -187,9 +198,10 @@
     @Test
     public void testDelegateChangingDeniedTagsChanged() throws Exception {
         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
-                mSipDelegate);
+                mSipDelegate, mRcsStats);
         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
-        stateTracker.sipDelegateConnected(deniedTags);
+        Set<String> supportedTags = getSupportedTags();
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
         // SipDelegate created
         verify(mAppCallback).onCreated(mSipDelegate);
         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -220,7 +232,7 @@
         // new underlying SipDelegate created, but SipDelegate denied one to one chat
         deniedTags.add(new FeatureTagState(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG,
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
-        stateTracker.sipDelegateConnected(deniedTags);
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
         DelegateRegistrationState fullyDeniedRegState = new DelegateRegistrationState.Builder()
                 .build();
         // In this special case, it will be the SipDelegateConnectionBase that will trigger
@@ -244,9 +256,10 @@
     @Test
     public void testDelegateChangingDeniedTagsChangingToDestroy() throws Exception {
         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
-                mSipDelegate);
+                mSipDelegate, mRcsStats);
         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
-        stateTracker.sipDelegateConnected(deniedTags);
+        Set<String> supportedTags = getSupportedTags();
+        stateTracker.sipDelegateConnected(supportedTags, deniedTags);
         // SipDelegate created
         verify(mAppCallback).onCreated(mSipDelegate);
         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -296,4 +309,11 @@
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
         return deniedTags;
     }
+
+    private Set<String> getSupportedTags() {
+        Set<String> supportedTags = new ArraySet<>();
+        supportedTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
+        supportedTags.add(ImsSignallingUtils.GROUP_CHAT_TAG);
+        return supportedTags;
+    }
 }
diff --git a/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java b/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
index 5b0e7c5..78f6894 100644
--- a/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
@@ -107,7 +107,8 @@
         assertTrue(future.get());
         verify(mMockMessageTracker).openTransport(mMockSipDelegate, request.getFeatureTags(),
                 Collections.emptySet());
-        verify(mMockDelegateStateTracker).sipDelegateConnected(Collections.emptySet());
+        verify(mMockDelegateStateTracker).sipDelegateConnected(request.getFeatureTags(),
+                Collections.emptySet());
     }
 
     @SmallTest
@@ -138,7 +139,7 @@
         allowedTags.removeAll(deniedTags.stream().map(FeatureTagState::getFeatureTag)
                 .collect(Collectors.toSet()));
         verify(mMockMessageTracker).openTransport(mMockSipDelegate, allowedTags, deniedTags);
-        verify(mMockDelegateStateTracker).sipDelegateConnected(deniedTags);
+        verify(mMockDelegateStateTracker).sipDelegateConnected(allowedTags, deniedTags);
     }
 
     @SmallTest
@@ -249,7 +250,9 @@
                 Collections.emptySet());
         verify(mMockMessageTracker).openTransport(mMockSipDelegate, newFts,
                 Collections.emptySet());
-        verify(mMockDelegateStateTracker, times(2)).sipDelegateConnected(Collections.emptySet());
+        verify(mMockDelegateStateTracker).sipDelegateConnected(
+                request.getFeatureTags(), Collections.emptySet());
+        verify(mMockDelegateStateTracker).sipDelegateConnected(newFts, Collections.emptySet());
     }
 
     private void createSipDelegate(DelegateRequest request, SipDelegateController controller)
diff --git a/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java b/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
index 823a8be..37abb83 100644
--- a/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
@@ -16,19 +16,28 @@
 
 package com.android.services.telephony.rcs;
 
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+
 import android.net.Uri;
 import android.telephony.ims.SipMessage;
 import android.util.Base64;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.internal.telephony.metrics.RcsStats;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -90,11 +99,104 @@
     // Keep track of the string entry so we can generate unique strings.
     private int mStringEntryCounter = 0;
     private SipSessionTracker mTrackerUT;
+    private static final int TEST_SUB_ID = 1;
+    private static final String TEST_INVITE_SIP_METHOD = "INVITE";
+    private static final int TEST_SIP_RESPONSE_CODE = 200;
+    private static final int TEST_SIP_CLOSE_RESPONSE_CODE = 0;
+    @Mock
+    private RcsStats mRcsStats;
 
     @Before
     public void setUp() {
         mStringEntryCounter = 0;
-        mTrackerUT = new SipSessionTracker();
+        MockitoAnnotations.initMocks(this);
+        mTrackerUT = new SipSessionTracker(TEST_SUB_ID, mRcsStats);
+    }
+
+    @Test
+    public void testMetricsEndedGracefullyBye() {
+        DialogAttributes attr = new DialogAttributes();
+        // INVITE
+        SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+        filterMessage(inviteRequest, attr);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+
+        // confirmed dialog
+        attr.setToTag();
+        SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+        filterMessage(inviteConfirm, attr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+
+        // Gracefully Ended
+        SipMessage inviteClose = generateSipRequest(SipMessageUtils.BYE_SIP_METHOD, attr);
+        filterMessage(inviteClose, attr);
+
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getClosedDialogs(), attr);
+
+        // verify Metrics information
+        verify(mRcsStats).onSipTransportSessionClosed(eq(TEST_SUB_ID), eq(attr.callId),
+                eq(TEST_SIP_CLOSE_RESPONSE_CODE), eq(true));
+    }
+
+    @Test
+    public void testMetricsCloseCleanupSession() {
+        //mTrackerUT.setRcsStats(mRcsStats);
+        DialogAttributes attr = new DialogAttributes();
+        // INVITE A -> B
+        SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+        filterMessage(inviteRequest, attr);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+
+        // confirmed dialog
+        attr.setToTag();
+        SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+        filterMessage(inviteConfirm, attr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+
+        //forcefully close session
+        mTrackerUT.cleanupSession(attr.callId);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+
+        // verify Metrics information
+        verify(mRcsStats).onSipTransportSessionClosed(eq(TEST_SUB_ID), eq(attr.callId),
+                eq(TEST_SIP_CLOSE_RESPONSE_CODE), eq(false));
+    }
+
+    @Test
+    public void testMetricsCloseClearAllSessions() {
+        //mTrackerUT.setRcsStats(mRcsStats);
+        DialogAttributes attr = new DialogAttributes();
+
+        // INVITE
+        SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+        filterMessage(inviteRequest, attr);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+
+        // confirmed dialog
+        attr.setToTag();
+        SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+        filterMessage(inviteConfirm, attr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+
+        //forcefully close session
+        mTrackerUT.clearAllSessions();
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+
+        // verify Metrics information
+        verify(mRcsStats).onSipTransportSessionClosed(eq(TEST_SUB_ID), eq(attr.callId),
+                eq(TEST_SIP_CLOSE_RESPONSE_CODE), eq(false));
     }
 
     @Test
@@ -291,7 +393,8 @@
     public void testAcknowledgeMessageFailed() {
         DialogAttributes attr = new DialogAttributes();
         SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
-        mTrackerUT.filterSipMessage(inviteRequest);
+        mTrackerUT.filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, inviteRequest);
         // Do not acknowledge the request and ensure that the operation has not been applied yet.
         assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
         assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
@@ -310,8 +413,10 @@
         // We unexpectedly received two filter requests for the same branchId without
         // acknowledgePendingMessage being called in between. Ensure that when it is called, it
         // applies both operations.
-        mTrackerUT.filterSipMessage(inviteRequest);
-        mTrackerUT.filterSipMessage(inviteConfirm);
+        mTrackerUT.filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, inviteRequest);
+        mTrackerUT.filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, inviteConfirm);
         assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
         assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
         // we should skip right to confirmed as both operations run back-to-back
@@ -321,7 +426,8 @@
     }
 
     private void filterMessage(SipMessage m, DialogAttributes attr) {
-        mTrackerUT.filterSipMessage(m);
+        mTrackerUT.filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, m);
         mTrackerUT.acknowledgePendingMessage(attr.branchId);
     }
     private void verifyContainsCallIds(Set<SipDialog> callIdSet, DialogAttributes... attrs) {
diff --git a/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java b/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
index 4d222e3..0fe897f 100644
--- a/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
+++ b/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
@@ -16,6 +16,9 @@
 
 package com.android.services.telephony.rcs;
 
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING;
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -23,6 +26,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.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;
 
@@ -37,6 +41,7 @@
 
 import com.android.TelephonyTestBase;
 import com.android.TestExecutorService;
+import com.android.internal.telephony.metrics.RcsStats;
 import com.android.services.telephony.rcs.validator.IncomingTransportStateValidator;
 import com.android.services.telephony.rcs.validator.OutgoingTransportStateValidator;
 import com.android.services.telephony.rcs.validator.ValidationResult;
@@ -76,6 +81,8 @@
     private IncomingTransportStateValidator mIncomingStateValidator;
     @Mock
     private OutgoingTransportStateValidator mOutgoingStateValidator;
+    @Mock
+    private RcsStats mRcsStats;
 
     @Before
     public void setUp() throws Exception {
@@ -117,12 +124,50 @@
     }
 
     @Test
+    public void testMetricsResponse() {
+        String testSipInviteMethod = "INVITE";
+        String testSipMessageMethod = "MESSAGE";
+        int testSipResponseCode = 200;
+        int testMessageError = 0;
+
+        TestExecutorService executor = new TestExecutorService();
+        TransportSipMessageValidator tracker = openTransport(executor);
+        // Since the incoming/outgoing messages were verified, there should have been two calls
+        // to filter the message.
+        verify(mSipSessionTracker).filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, TEST_MESSAGE);
+        verify(mSipSessionTracker).filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, TEST_MESSAGE);
+
+        assertTrue(tracker.verifyOutgoingMessage(generateSipRequest("INVITE",
+                "testId1"), TEST_CONFIG_VERSION).isValidated);
+        verify(mRcsStats).onSipMessageRequest(eq("testId1"),
+                eq(testSipInviteMethod),
+                eq(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING));
+
+        assertTrue(tracker.verifyOutgoingMessage(generateSipRequest("MESSAGE",
+                "testId2"), TEST_CONFIG_VERSION).isValidated);
+        verify(mRcsStats).onSipMessageRequest(eq("testId2"),
+                eq(testSipMessageMethod),
+                eq(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING));
+
+        assertTrue(tracker.verifyIncomingMessage(
+                 generateSipResponse("200", "OK", "testId2"))
+                 .isValidated);
+        verify(mRcsStats).onSipMessageResponse(eq(TEST_SUB_ID), eq("testId2"),
+                eq(testSipResponseCode), eq(testMessageError));
+    }
+
+    @Test
     public void testSessionTrackerFiltering() {
         TestExecutorService executor = new TestExecutorService();
         TransportSipMessageValidator tracker = openTransport(executor);
         // Since the incoming/outgoing messages were verified, there should have been two calls
         // to filter the message.
-        verify(mSipSessionTracker, times(2)).filterSipMessage(TEST_MESSAGE);
+        verify(mSipSessionTracker).filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, TEST_MESSAGE);
+        verify(mSipSessionTracker).filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, TEST_MESSAGE);
         // ensure pass through methods are working
         tracker.acknowledgePendingMessage("abc");
         verify(mSipSessionTracker).acknowledgePendingMessage("abc");
@@ -140,7 +185,10 @@
         assertFalse(tracker.verifyOutgoingMessage(TEST_MESSAGE, TEST_CONFIG_VERSION).isValidated);
         // The number of times the filter method was called should still only be two after these
         // messages were not validated.
-        verify(mSipSessionTracker, times(2)).filterSipMessage(TEST_MESSAGE);
+        verify(mSipSessionTracker).filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, TEST_MESSAGE);
+        verify(mSipSessionTracker).filterSipMessage(
+                SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, TEST_MESSAGE);
     }
 
 
@@ -482,6 +530,27 @@
         doReturn(ValidationResult.SUCCESS).when(mIncomingStateValidator).validate(any());
         doReturn(mIncomingStateValidator).when(mIncomingStateValidator).andThen(any());
         return new TransportSipMessageValidator(TEST_SUB_ID, executor, mSipSessionTracker,
-                mOutgoingStateValidator, mIncomingStateValidator);
+                mOutgoingStateValidator, mIncomingStateValidator, mRcsStats);
+    }
+
+    private SipMessage generateSipResponse(String statusCode, String statusString, String callId) {
+        String fromHeader = "Alice <sip:alice@atlanta.com>;tag=1928301774";
+        String toHeader = "Bob <sip:bob@biloxi.com>";
+        String branchId = "AAAA";
+        String fromTag = "tag=1928301774";
+        String toTag = "";
+        return SipMessageUtils.generateSipResponse(statusCode, statusString, fromHeader,
+            toHeader, branchId, callId, fromTag, toTag);
+    }
+
+    private SipMessage generateSipRequest(String requestMethod, String callId) {
+        String fromHeader = "Alice <sip:alice@atlanta.com>;tag=1928301774";
+        String toHeader = "Bob <sip:bob@biloxi.com>";
+        String branchId = "AAAA";
+        String fromTag = "tag=1928301774";
+        String toTag = "";
+        String toUri = "sip:bob@biloxi.com";
+        return SipMessageUtils.generateSipRequest(requestMethod, fromHeader, toHeader,
+                toUri, branchId, callId, fromTag, toTag);
     }
 }