Merge "Show phone numbers from all sources in hidden menu"
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index c941be2..22aa185 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -890,14 +890,14 @@
     <string name="radio_info_ppp_resets_label" msgid="9131901102339077661">"चालू करने के बाद से पीपीपी रीसेट की संख्या:"</string>
     <string name="radio_info_current_network_label" msgid="3052098695239642450">"मौजूदा नेटवर्क:"</string>
     <string name="radio_info_ppp_received_label" msgid="5753592451640644889">"मिलने वाला डेटा :"</string>
-    <string name="radio_info_gsm_service_label" msgid="6443348321714241328">"Voice की सेवा:"</string>
+    <string name="radio_info_gsm_service_label" msgid="6443348321714241328">"वॉइस सेवा:"</string>
     <string name="radio_info_signal_strength_label" msgid="5545444702102543260">"सिग्नल कितना अच्छा है:"</string>
-    <string name="radio_info_call_status_label" msgid="7693575431923095487">"Voice कॉल की स्थिति:"</string>
+    <string name="radio_info_call_status_label" msgid="7693575431923095487">"वॉइस कॉल की स्थिति:"</string>
     <string name="radio_info_ppp_sent_label" msgid="6542208429356199695">"भेजा गया डेटा :"</string>
     <string name="radio_info_message_waiting_label" msgid="1886549432566952078">"मैसेज वेटिंग:"</string>
     <string name="radio_info_phone_number_label" msgid="2533852539562512203">"फ़ोन नंबर:"</string>
     <string name="radio_info_band_mode_label" msgid="23480556225515290">"रेडियो का बैंड चुनें"</string>
-    <string name="radio_info_voice_network_type_label" msgid="2395347336419593265">"Voice के नेटवर्क प्रकार:"</string>
+    <string name="radio_info_voice_network_type_label" msgid="2395347336419593265">"वॉइस नेटवर्क टाइप:"</string>
     <string name="radio_info_data_network_type_label" msgid="8886597029237501929">"डेटा नेटवर्क प्रकार:"</string>
     <string name="phone_index_label" msgid="6222406512768964268">"फ़ोन इंडेक्स चुनें"</string>
     <string name="radio_info_set_perferred_label" msgid="7408131389363136210">"पसंदीदा नेटवर्क प्रकार सेट करें:"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 18ee718..06af4bc 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -297,7 +297,7 @@
     <string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"Account SIP deprecati trovati e rimossi"</string>
     <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"Le chiamate SIP non sono più supportate dalla piattaforma Android.\nI tuoi account SIP esistenti (<xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g>) sono stati rimossi.\nConferma l\'impostazione del tuo account predefinito per le chiamate."</string>
     <string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"Vai alle impostazioni"</string>
-    <string name="data_usage_title" msgid="8438592133893837464">"Utilizzo dei dati delle app"</string>
+    <string name="data_usage_title" msgid="8438592133893837464">"Utilizzo dati delle app"</string>
     <string name="data_usage_template" msgid="6287906680674061783">"Dati mobili usati: <xliff:g id="ID_1">%1$s</xliff:g> nel periodo <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="advanced_options_title" msgid="9208195294513520934">"Avanzate"</string>
     <string name="carrier_settings_euicc" msgid="1190237227261337749">"Operatore"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 850bfbb..226dc72 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -846,9 +846,9 @@
     <string name="dsds_dialog_confirm" msgid="9032004888134129885">"Opnieuw opstarten"</string>
     <string name="dsds_dialog_cancel" msgid="3245958947099586655">"Annuleren"</string>
     <string name="radio_info_radio_power" msgid="8805595022160471587">"Mobiel radiovermogen"</string>
-    <string name="radioInfo_menu_viewADN" msgid="4533179730908559846">"Adresboek op simkaart weergeven"</string>
-    <string name="radioInfo_menu_viewFDN" msgid="1847236480527032061">"Vaste nummers weergeven"</string>
-    <string name="radioInfo_menu_viewSDN" msgid="2613431584522392842">"Servicenummers weergeven"</string>
+    <string name="radioInfo_menu_viewADN" msgid="4533179730908559846">"Adresboek op simkaart bekijken"</string>
+    <string name="radioInfo_menu_viewFDN" msgid="1847236480527032061">"Vaste nummers bekijken"</string>
+    <string name="radioInfo_menu_viewSDN" msgid="2613431584522392842">"Servicenummers bekijken"</string>
     <string name="radioInfo_menu_getIMS" msgid="1950869267853198232">"IMS-servicestatus"</string>
     <string name="radio_info_ims_reg_status_title" msgid="6875885401313992007">"IMS-status"</string>
     <string name="radio_info_ims_reg_status_registered" msgid="7095182114078864326">"Geregistreerd"</string>
diff --git a/src/com/android/phone/ImsStateCallbackController.java b/src/com/android/phone/ImsStateCallbackController.java
index c7f15bf..28fca59 100644
--- a/src/com/android/phone/ImsStateCallbackController.java
+++ b/src/com/android/phone/ImsStateCallbackController.java
@@ -47,6 +47,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyRegistryManager;
 import android.telephony.ims.feature.ImsFeature;
+import android.util.LocalLog;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -60,6 +61,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.telephony.util.HandlerExecutor;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.services.telephony.rcs.RcsFeatureController;
 import com.android.telephony.Rlog;
 
@@ -74,6 +76,7 @@
 public class ImsStateCallbackController {
     private static final String TAG = "ImsStateCallbackController";
     private static final boolean VDBG = false;
+    private static final int LOG_SIZE = 50;
 
     /**
      * Create a FeatureConnector for this class to use to connect to an ImsManager.
@@ -123,6 +126,7 @@
     private static final int EVENT_MSIM_CONFIGURATION_CHANGE = 6;
 
     private static ImsStateCallbackController sInstance;
+    private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
 
     /**
      * get the instance
@@ -146,6 +150,8 @@
 
     private HashMap<IBinder, CallbackWrapper> mWrappers = new HashMap<>();
 
+    private final Object mDumpLock = new Object();
+
     private int mNumSlots;
 
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -197,41 +203,43 @@
 
         @Override
         public void handleMessage(Message msg) {
-            logv("handleMessage: " + msg);
-            switch (msg.what) {
-                case EVENT_SUB_CHANGED:
-                    onSubChanged();
-                    break;
-
-                case EVENT_REGISTER_CALLBACK:
-                    onRegisterCallback((ImsStateCallbackController.CallbackWrapper) msg.obj);
-                    break;
-
-                case EVENT_UNREGISTER_CALLBACK:
-                    onUnregisterCallback((IImsStateCallback) msg.obj);
-                    break;
-
-                case EVENT_CARRIER_CONFIG_CHANGED:
-                    onCarrierConfigChanged(msg.arg1);
-                    break;
-
-                case EVENT_EXTERNAL_RCS_STATE_CHANGED:
-                    if (msg.obj == null) break;
-                    onExternalRcsStateChanged((ExternalRcsFeatureState) msg.obj);
-                    break;
-
-                case EVENT_MSIM_CONFIGURATION_CHANGE:
-                    AsyncResult result = (AsyncResult) msg.obj;
-                    Integer numSlots = (Integer) result.result;
-                    if (numSlots == null) {
-                        Log.w(TAG, "msim config change with null num slots");
+            if (VDBG) logv("handleMessage: " + msg);
+            synchronized (mDumpLock) {
+                switch (msg.what) {
+                    case EVENT_SUB_CHANGED:
+                        onSubChanged();
                         break;
-                    }
-                    updateFeatureControllerSize(numSlots);
-                    break;
 
-                default:
-                    loge("Unhandled event " + msg.what);
+                    case EVENT_REGISTER_CALLBACK:
+                        onRegisterCallback((ImsStateCallbackController.CallbackWrapper) msg.obj);
+                        break;
+
+                    case EVENT_UNREGISTER_CALLBACK:
+                        onUnregisterCallback((IImsStateCallback) msg.obj);
+                        break;
+
+                    case EVENT_CARRIER_CONFIG_CHANGED:
+                        onCarrierConfigChanged(msg.arg1);
+                        break;
+
+                    case EVENT_EXTERNAL_RCS_STATE_CHANGED:
+                        if (msg.obj == null) break;
+                        onExternalRcsStateChanged((ExternalRcsFeatureState) msg.obj);
+                        break;
+
+                    case EVENT_MSIM_CONFIGURATION_CHANGE:
+                        AsyncResult result = (AsyncResult) msg.obj;
+                        Integer numSlots = (Integer) result.result;
+                        if (numSlots == null) {
+                            Log.w(TAG, "msim config change with null num slots");
+                            break;
+                        }
+                        updateFeatureControllerSize(numSlots);
+                        break;
+
+                    default:
+                        loge("Unhandled event " + msg.what);
+                }
             }
         }
     }
@@ -260,23 +268,25 @@
         private String mLogPrefix = "";
 
         MmTelFeatureListener(int slotId) {
-            mLogPrefix = "[MMTEL, " + slotId + "] ";
-            logv(mLogPrefix + "create");
+            mSlotId = slotId;
+            mLogPrefix = "[" + slotId + ", MMTEL] ";
+            if (VDBG) logv(mLogPrefix + "created");
+
             mConnector = mMmTelFeatureFactory.create(
                     mApp, slotId, TAG, this, new HandlerExecutor(mHandler));
             mConnector.connect();
         }
 
         void setSubId(int subId) {
-            logv(mLogPrefix + "setSubId mSubId=" + mSubId + ", subId=" + subId);
+            if (VDBG) logv(mLogPrefix + "setSubId mSubId=" + mSubId + ", subId=" + subId);
             if (mSubId == subId) return;
-            logd(mLogPrefix + "setSubId subId changed");
+            logd(mLogPrefix + "setSubId changed subId=" + subId);
 
             mSubId = subId;
         }
 
         void destroy() {
-            logv(mLogPrefix + "destroy");
+            if (VDBG) logv(mLogPrefix + "destroy");
             mConnector.disconnect();
             mConnector = null;
         }
@@ -345,10 +355,19 @@
 
         // called from onRegisterCallback
         boolean notifyState(CallbackWrapper wrapper) {
-            logv(mLogPrefix + "notifyState subId=" + wrapper.mSubId);
+            if (VDBG) logv(mLogPrefix + "notifyState subId=" + wrapper.mSubId);
 
             return wrapper.notifyState(mSubId, FEATURE_MMTEL, mState, mReason);
         }
+
+        void dump(IndentingPrintWriter pw) {
+            pw.println("Listener={slotId=" + mSlotId
+                    + ", subId=" + mSubId
+                    + ", state=" + ImsFeature.STATE_LOG_MAP.get(mState)
+                    + ", reason=" + imsStateReasonToString(mReason)
+                    + ", hasConfig=" + mHasConfig
+                    + "}");
+        }
     }
 
     private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> {
@@ -390,8 +409,9 @@
         private String mLogPrefix = "";
 
         RcsFeatureListener(int slotId) {
-            mLogPrefix = "[RCS, " + slotId + "] ";
-            logv(mLogPrefix + "create");
+            mSlotId = slotId;
+            mLogPrefix = "[" + slotId + ", RCS] ";
+            if (VDBG) logv(mLogPrefix + "created");
 
             mConnector = mRcsFeatureFactory.create(
                     mApp, slotId, this, new HandlerExecutor(mHandler), TAG);
@@ -399,15 +419,15 @@
         }
 
         void setSubId(int subId) {
-            logv(mLogPrefix + "setSubId mSubId=" + mSubId + ", subId=" + subId);
+            if (VDBG) logv(mLogPrefix + "setSubId mSubId=" + mSubId + ", subId=" + subId);
             if (mSubId == subId) return;
-            logd(mLogPrefix + "setSubId subId changed");
+            logd(mLogPrefix + "setSubId changed subId=" + subId);
 
             mSubId = subId;
         }
 
         void destroy() {
-            logv(mLogPrefix + "destroy");
+            if (VDBG) logv(mLogPrefix + "destroy");
 
             mConnector.disconnect();
             mConnector = null;
@@ -450,7 +470,7 @@
             }
 
             if (mExternalState != null && !mExternalState.hasActiveFeatures()) {
-                // notifyExternalState has notified REASON_NO_IMS_SERVICE_CONFIGURED already
+                // notifyExternalRcsState has notified REASON_NO_IMS_SERVICE_CONFIGURED already
                 // ignore it
                 return;
             }
@@ -493,10 +513,12 @@
         }
 
         void notifyExternalRcsState(ExternalRcsFeatureState fs) {
-            logv(mLogPrefix + "notifyExternalRcsState"
-                    + " state=" + (fs.mState == STATE_UNKNOWN
-                            ? "" : ImsFeature.STATE_LOG_MAP.get(fs.mState))
-                    + ", reason=" + imsStateReasonToString(fs.mReason));
+            if (VDBG) {
+                logv(mLogPrefix + "notifyExternalRcsState"
+                        + " state=" + (fs.mState == STATE_UNKNOWN
+                                ? "" : ImsFeature.STATE_LOG_MAP.get(fs.mState))
+                        + ", reason=" + imsStateReasonToString(fs.mReason));
+            }
 
             ExternalRcsFeatureState oldFs = mExternalState;
             // External state is from TelephonyRcsService while a feature is added or removed.
@@ -539,7 +561,7 @@
 
         // called from onRegisterCallback
         boolean notifyState(CallbackWrapper wrapper) {
-            logv(mLogPrefix + "notifyState subId=" + wrapper.mSubId);
+            if (VDBG) logv(mLogPrefix + "notifyState subId=" + wrapper.mSubId);
 
             if (mHasConfig) {
                 if (mExternalState == null) {
@@ -554,6 +576,18 @@
 
             return wrapper.notifyState(mSubId, FEATURE_RCS, mState, mReason);
         }
+
+        void dump(IndentingPrintWriter pw) {
+            pw.println("Listener={slotId=" + mSlotId
+                    + ", subId=" + mSubId
+                    + ", state=" + ImsFeature.STATE_LOG_MAP.get(mState)
+                    + ", reason=" + imsStateReasonToString(mReason)
+                    + ", hasConfig=" + mHasConfig
+                    + ", isReady=" + (mExternalState == null ? false : mExternalState.isReady())
+                    + ", hasFeatures=" + (mExternalState == null ? false
+                            : mExternalState.hasActiveFeatures())
+                    + "}");
+        }
     }
 
     /**
@@ -564,12 +598,16 @@
         private final int mRequiredFeature;
         private final IImsStateCallback mCallback;
         private final IBinder mBinder;
+        private final String mCallingPackage;
+        private int mLastReason = NOT_INITIALIZED;
 
-        CallbackWrapper(int subId, int feature, IImsStateCallback callback) {
+        CallbackWrapper(int subId, int feature, IImsStateCallback callback,
+                String callingPackage) {
             mSubId = subId;
             mRequiredFeature = feature;
             mCallback = callback;
             mBinder = callback.asBinder();
+            mCallingPackage = callingPackage;
         }
 
         /**
@@ -579,10 +617,12 @@
          * This instance shall be removed from the list.
          */
         boolean notifyState(int subId, int feature, int state, int reason) {
-            logv("CallbackWrapper notifyState subId=" + subId
-                    + ", feature=" + ImsFeature.FEATURE_LOG_MAP.get(feature)
-                    + ", state=" + ImsFeature.STATE_LOG_MAP.get(state)
-                    + ", reason=" + imsStateReasonToString(reason));
+            if (VDBG) {
+                logv("CallbackWrapper notifyState subId=" + subId
+                        + ", feature=" + ImsFeature.FEATURE_LOG_MAP.get(feature)
+                        + ", state=" + ImsFeature.STATE_LOG_MAP.get(state)
+                        + ", reason=" + imsStateReasonToString(reason));
+            }
 
             try {
                 if (state == STATE_READY) {
@@ -590,6 +630,7 @@
                 } else {
                     mCallback.onUnavailable(reason);
                 }
+                mLastReason = reason;
             } catch (Exception e) {
                 loge("CallbackWrapper notifyState e=" + e);
                 return false;
@@ -599,7 +640,7 @@
         }
 
         void notifyInactive() {
-            logv("CallbackWrapper notifyInactive subId=" + mSubId);
+            if (VDBG) logv("CallbackWrapper notifyInactive subId=" + mSubId);
 
             try {
                 mCallback.onUnavailable(REASON_SUBSCRIPTION_INACTIVE);
@@ -607,6 +648,14 @@
                 // ignored
             }
         }
+
+        void dump(IndentingPrintWriter pw) {
+            pw.println("CallbackWrapper={subId=" + mSubId
+                    + ", feature=" + ImsFeature.FEATURE_LOG_MAP.get(mRequiredFeature)
+                    + ", reason=" + imsStateReasonToString(mLastReason)
+                    + ", pkg=" + mCallingPackage
+                    + "}");
+        }
     }
 
     private static class ExternalRcsFeatureState {
@@ -680,7 +729,7 @@
     @VisibleForTesting
     public void updateFeatureControllerSize(int newNumSlots) {
         if (mNumSlots != newNumSlots) {
-            Log.d(TAG, "updateFeatures: oldSlots=" + mNumSlots
+            logd("updateFeatures: oldSlots=" + mNumSlots
                     + ", newNumSlots=" + newNumSlots);
             if (mNumSlots < newNumSlots) {
                 for (int i = mNumSlots; i < newNumSlots; i++) {
@@ -712,8 +761,6 @@
      */
     @VisibleForTesting
     public void onSubChanged() {
-        logv("onSubChanged size=" + mWrappers.size());
-
         for (int i = 0; i < mMmTelFeatureListeners.size(); i++) {
             MmTelFeatureListener l = mMmTelFeatureListeners.valueAt(i);
             l.setSubId(getSubId(i));
@@ -729,7 +776,7 @@
         ArrayList<IBinder> inactiveCallbacks = new ArrayList<>();
         final int[] activeSubs = mSubscriptionManager.getActiveSubscriptionIdList();
 
-        logv("onSubChanged activeSubs=" + Arrays.toString(activeSubs));
+        if (VDBG) logv("onSubChanged activeSubs=" + Arrays.toString(activeSubs));
 
         // Remove callbacks for inactive subscriptions
         for (IBinder binder : mWrappers.keySet()) {
@@ -748,10 +795,12 @@
     }
 
     private void onFeatureStateChange(int subId, int feature, int state, int reason) {
-        logv("onFeatureStateChange subId=" + subId
-                + ", feature=" + ImsFeature.FEATURE_LOG_MAP.get(feature)
-                + ", state=" + ImsFeature.STATE_LOG_MAP.get(state)
-                + ", reason=" + imsStateReasonToString(reason));
+        if (VDBG) {
+            logv("onFeatureStateChange subId=" + subId
+                    + ", feature=" + ImsFeature.FEATURE_LOG_MAP.get(feature)
+                    + ", state=" + ImsFeature.STATE_LOG_MAP.get(state)
+                    + ", reason=" + imsStateReasonToString(reason));
+        }
 
         ArrayList<IBinder> inactiveCallbacks = new ArrayList<>();
         mWrappers.values().forEach(wrapper -> {
@@ -768,9 +817,11 @@
     private void onRegisterCallback(CallbackWrapper wrapper) {
         if (wrapper == null) return;
 
-        logv("onRegisterCallback before size=" + mWrappers.size());
-        logv("onRegisterCallback subId=" + wrapper.mSubId
-                + ", feature=" + wrapper.mRequiredFeature);
+        if (VDBG) logv("onRegisterCallback before size=" + mWrappers.size());
+        if (VDBG) {
+            logv("onRegisterCallback subId=" + wrapper.mSubId
+                    + ", feature=" + wrapper.mRequiredFeature);
+        }
 
         // Not sure the following case can happen or not:
         // step1) Subscription changed
@@ -801,7 +852,7 @@
             }
         }
 
-        logv("onRegisterCallback after size=" + mWrappers.size());
+        if (VDBG) logv("onRegisterCallback after size=" + mWrappers.size());
     }
 
     private void onUnregisterCallback(IImsStateCallback cb) {
@@ -816,7 +867,7 @@
             return;
         }
 
-        logd("onCarrierConfigChanged slotId=" + slotId);
+        logv("onCarrierConfigChanged slotId=" + slotId);
 
         boolean hasConfig = verifyImsMmTelConfigured(slotId);
         if (slotId < mMmTelFeatureListeners.size()) {
@@ -871,9 +922,11 @@
             // Only when there is no feature, we can assume the state.
         }
 
-        logv("notifyExternalRcsStateChanged slotId=" + slotId
-                + ", ready=" + ready
-                + ", hasActiveFeatures=" + hasActiveFeatures);
+        if (VDBG) {
+            logv("notifyExternalRcsStateChanged slotId=" + slotId
+                    + ", ready=" + ready
+                    + ", hasActiveFeatures=" + hasActiveFeatures);
+        }
 
         ExternalRcsFeatureState fs = new ExternalRcsFeatureState(slotId, state, reason);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_EXTERNAL_RCS_STATE_CHANGED, fs));
@@ -884,7 +937,7 @@
      */
     @VisibleForTesting
     public void notifyCarrierConfigChanged(int slotId) {
-        logv("notifyCarrierConfigChanged slotId=" + slotId);
+        if (VDBG) logv("notifyCarrierConfigChanged slotId=" + slotId);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARRIER_CONFIG_CHANGED, slotId, 0));
     }
     /**
@@ -892,10 +945,14 @@
      *
      * @param feature for which state is changed, ImsFeature.FEATURE_*
      */
-    public void registerImsStateCallback(int subId, int feature, IImsStateCallback cb) {
-        logv("registerImsStateCallback subId=" + subId + ", feature=" + feature);
+    public void registerImsStateCallback(int subId, int feature, IImsStateCallback cb,
+            String callingPackage) {
+        if (VDBG) {
+            logv("registerImsStateCallback subId=" + subId
+                    + ", feature=" + feature + ", pkg=" + callingPackage);
+        }
 
-        CallbackWrapper wrapper = new CallbackWrapper(subId, feature, cb);
+        CallbackWrapper wrapper = new CallbackWrapper(subId, feature, cb, callingPackage);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_CALLBACK, wrapper));
     }
 
@@ -903,7 +960,7 @@
      * Unegister previously registered callback
      */
     public void unregisterImsStateCallback(IImsStateCallback cb) {
-        logv("unregisterImsStateCallback");
+        if (VDBG) logv("unregisterImsStateCallback");
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_CALLBACK, cb));
     }
@@ -912,7 +969,10 @@
             ArrayList<IBinder> inactiveCallbacks, String message) {
         if (inactiveCallbacks == null || inactiveCallbacks.size() == 0) return;
 
-        logv("removeInactiveCallbacks size=" + inactiveCallbacks.size() + " from " + message);
+        if (VDBG) {
+            logv("removeInactiveCallbacks size="
+                    + inactiveCallbacks.size() + " from " + message);
+        }
 
         for (IBinder binder : inactiveCallbacks) {
             CallbackWrapper wrapper = mWrappers.get(binder);
@@ -958,7 +1018,7 @@
         } else {
             ret = mImsResolver.isImsServiceConfiguredForFeature(slotId, FEATURE_MMTEL);
         }
-        logv("verifyImsMmTelConfigured slotId=" + slotId + ", ret=" + ret);
+        if (VDBG) logv("verifyImsMmTelConfigured slotId=" + slotId + ", ret=" + ret);
         return ret;
     }
 
@@ -969,7 +1029,7 @@
         } else {
             ret = mImsResolver.isImsServiceConfiguredForFeature(slotId, FEATURE_RCS);
         }
-        logv("verifyImsRcsConfigured slotId=" + slotId + ", ret=" + ret);
+        if (VDBG) logv("verifyImsRcsConfigured slotId=" + slotId + ", ret=" + ret);
         return ret;
     }
 
@@ -991,6 +1051,8 @@
 
     private static String imsStateReasonToString(int reason) {
         switch(reason) {
+            case AVAILABLE:
+                return "READY";
             case REASON_UNKNOWN_TEMPORARY_ERROR:
                 return "UNKNOWN_TEMPORARY_ERROR";
             case REASON_UNKNOWN_PERMANENT_ERROR:
@@ -1028,7 +1090,7 @@
     };
 
     private void release() {
-        logv("release");
+        if (VDBG) logv("release");
 
         mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener);
         mApp.unregisterReceiver(mReceiver);
@@ -1049,7 +1111,7 @@
      */
     @VisibleForTesting
     public void destroy() {
-        logv("destroy it");
+        if (VDBG) logv("destroy it");
 
         release();
         mHandler.getLooper().quit();
@@ -1072,17 +1134,51 @@
         return mWrappers.containsKey(cb.asBinder());
     }
 
-    private static void logv(String msg) {
-        if (VDBG) {
-            Rlog.d(TAG, msg);
+    /**
+     * Dump this instance into a readable format for dumpsys usage.
+     */
+    public void dump(IndentingPrintWriter pw) {
+        pw.increaseIndent();
+        synchronized (mDumpLock) {
+            pw.println("CallbackWrappers:");
+            pw.increaseIndent();
+            mWrappers.values().forEach(wrapper -> wrapper.dump(pw));
+            pw.decreaseIndent();
+            pw.println("MmTelFeatureListeners:");
+            pw.increaseIndent();
+            for (int i = 0; i < mNumSlots; i++) {
+                MmTelFeatureListener l = mMmTelFeatureListeners.get(i);
+                if (l == null) continue;
+                l.dump(pw);
+            }
+            pw.decreaseIndent();
+            pw.println("RcsFeatureListeners:");
+            pw.increaseIndent();
+            for (int i = 0; i < mNumSlots; i++) {
+                RcsFeatureListener l = mRcsFeatureListeners.get(i);
+                if (l == null) continue;
+                l.dump(pw);
+            }
+            pw.decreaseIndent();
+            pw.println("Most recent logs:");
+            pw.increaseIndent();
+            sLocalLog.dump(pw);
+            pw.decreaseIndent();
         }
+        pw.decreaseIndent();
+    }
+
+    private static void logv(String msg) {
+        Rlog.d(TAG, msg);
     }
 
     private static void logd(String msg) {
         Rlog.d(TAG, msg);
+        sLocalLog.log(msg);
     }
 
     private static void loge(String msg) {
         Rlog.e(TAG, msg);
+        sLocalLog.log(msg);
     }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 9607919..e7cb28c 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -1038,6 +1038,12 @@
         } catch (Exception e) {
             e.printStackTrace();
         }
+        pw.println("ImsStateCallbackController:");
+        try {
+            if (mImsStateCallbackController != null) mImsStateCallbackController.dump(pw);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         pw.decreaseIndent();
         pw.println("------- End PhoneGlobals -------");
     }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 55452f3..3721c40 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -28,10 +28,13 @@
 import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.compat.CompatChanges;
 import android.app.role.RoleManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -105,7 +108,9 @@
 import android.telephony.TelephonyScanManager;
 import android.telephony.ThermalMitigationRequest;
 import android.telephony.UiccCardInfo;
+import android.telephony.UiccPortInfo;
 import android.telephony.UiccSlotInfo;
+import android.telephony.UiccSlotMapping;
 import android.telephony.UssdResponse;
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import android.telephony.data.ApnSetting;
@@ -218,6 +223,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -404,6 +410,16 @@
             "reset_network_erase_modem_config_enabled";
 
     private static final int SET_NETWORK_SELECTION_MODE_AUTOMATIC_TIMEOUT_MS = 2000; // 2 seconds
+    /**
+     * With support for MEP(multiple enabled profile) in Android T, a SIM card can have more than
+     * one ICCID active at the same time.
+     * Apps should use below API signatures if targeting SDK is T and beyond.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    public static final long GET_API_SIGNATURES_FROM_UICC_PORT_INFO = 202110963L;
 
     /**
      * A request object to use for transmitting data to an ICC.
@@ -8711,6 +8727,7 @@
                 .checkPackage(Binder.getCallingUid(), callingPackage);
 
         boolean hasReadPermission = false;
+        boolean isIccIdAccessRestricted = false;
         try {
             enforceReadPrivilegedPermission("getUiccCardsInfo");
             hasReadPermission = true;
@@ -8722,7 +8739,11 @@
                 throw new SecurityException("Caller does not have permission.");
             }
         }
-
+        // checking compatibility, if calling app's target SDK is T and beyond.
+        if (CompatChanges.isChangeEnabled(GET_API_SIGNATURES_FROM_UICC_PORT_INFO,
+                Binder.getCallingUid())) {
+            isIccIdAccessRestricted = true;
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
             UiccController uiccController = UiccController.getInstance();
@@ -8734,21 +8755,23 @@
             // Remove private info if the caller doesn't have access
             ArrayList<UiccCardInfo> filteredInfos = new ArrayList<>();
             for (UiccCardInfo cardInfo : cardInfos) {
+                //setting the value after compatibility check
+                cardInfo.setIccIdAccessRestricted(isIccIdAccessRestricted);
                 // For an inactive eUICC, the UiccCard will be null even though the UiccCardInfo
                 // is available
-                UiccCard card = uiccController.getUiccCardForSlot(cardInfo.getSlotIndex());
+                UiccCard card = uiccController.getUiccCardForSlot(cardInfo.getPhysicalSlotIndex());
                 // TODO remove card.getUiccPortList().length once MEP API refactoring CL is merged
                 //  Get UiccPortInfo from CardInfo and process further based on each UiccPort
                 if (card == null || card.getUiccPortList().length == 0) {
                     // assume no access if the card or ports are unavailable
-                    filteredInfos.add(cardInfo.getUnprivileged());
+                    filteredInfos.add(getUiccCardInfoUnPrivileged(cardInfo));
                     continue;
                 }
 
                 if (haveCarrierPrivilegeAccess(card, callingPackage)) {
                     filteredInfos.add(cardInfo);
                 } else {
-                    filteredInfos.add(cardInfo.getUnprivileged());
+                    filteredInfos.add(getUiccCardInfoUnPrivileged(cardInfo));
                 }
             }
             return filteredInfos;
@@ -8757,10 +8780,70 @@
         }
     }
 
-    @Override
-    public UiccSlotInfo[] getUiccSlotsInfo() {
-        enforceReadPrivilegedPermission("getUiccSlotsInfo");
+    /**
+     * Returns a copy of the UiccCardinfo with the EID and ICCID set to null. These values are
+     * generally private and require carrier privileges to view.
+     *
+     * @hide
+     */
+    @NonNull
+    public UiccCardInfo getUiccCardInfoUnPrivileged(UiccCardInfo cardInfo) {
+        List<UiccPortInfo> portinfo = new  ArrayList<>();
+        for (UiccPortInfo portinfos : cardInfo.getPorts()) {
+            portinfo.add(getUiccPortInfoUnPrivileged(portinfos));
+        }
+        return new UiccCardInfo(
+                cardInfo.isEuicc(),
+                cardInfo.getCardId(),
+                null,
+                cardInfo.getPhysicalSlotIndex(),
+                cardInfo.isRemovable(),
+                cardInfo.isMultipleEnabledProfilesSupported(),
+                portinfo
+        );
+    }
 
+    /**
+     * @hide
+     * @return a copy of the UiccPortInfo with ICCID set to {@link UiccPortInfo#ICCID_REDACTED}.
+     * These values are generally private and require carrier privileges to view.
+     */
+    @NonNull
+    public UiccPortInfo getUiccPortInfoUnPrivileged(UiccPortInfo portInfo) {
+        return new UiccPortInfo(
+                UiccPortInfo.ICCID_REDACTED,
+                portInfo.getPortIndex(),
+                portInfo.getLogicalSlotIndex(),
+                portInfo.isActive()
+        );
+    }
+    @Override
+    public UiccSlotInfo[] getUiccSlotsInfo(String callingPackage) {
+        // Verify that tha callingPackage belongs to the calling UID
+        mApp.getSystemService(AppOpsManager.class)
+                .checkPackage(Binder.getCallingUid(), callingPackage);
+
+        boolean hasReadPermission = false;
+        boolean isLogicalSlotAccessRestricted = false;
+        String iccId;
+
+        try {
+            enforceReadPrivilegedPermission("getUiccSlotsInfo");
+            hasReadPermission = true;
+        } catch (SecurityException e) {
+            // even without READ_PRIVILEGED_PHONE_STATE, we allow the call to continue if the caller
+            // has carrier privileges on an active UICC
+            if (checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
+                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                hasReadPermission = true;
+            }
+        }
+
+        // checking compatibility, if calling app's target SDK is T and beyond.
+        if (CompatChanges.isChangeEnabled(GET_API_SIGNATURES_FROM_UICC_PORT_INFO,
+                Binder.getCallingUid())) {
+            isLogicalSlotAccessRestricted  = true;
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
             UiccSlot[] slots = UiccController.getInstance().getUiccSlots();
@@ -8768,7 +8851,6 @@
                 Rlog.i(LOG_TAG, "slots is null.");
                 return null;
             }
-
             UiccSlotInfo[] infos = new UiccSlotInfo[slots.length];
             for (int i = 0; i < slots.length; i++) {
                 UiccSlot slot = slots[i];
@@ -8778,12 +8860,24 @@
 
                 String cardId;
                 UiccCard card = slot.getUiccCard();
+                //if has read permission
+                if (hasReadPermission) {
+                    iccId = slot.getIccId();
+                } else {
+                    // if no read permission checking carrier
+                    if (haveCarrierPrivilegeAccess(card, callingPackage)) {
+                        iccId = slot.getIccId();
+                    } else {
+                        //if no carrier permission redact ICCID
+                        iccId = IccUtils.TEST_ICCID;
+                    }
+                }
                 if (card != null) {
                     cardId = card.getCardId();
                 } else {
                     cardId = slot.getEid();
                     if (TextUtils.isEmpty(cardId)) {
-                        cardId = slot.getIccId();
+                        cardId = iccId;
                     }
                 }
 
@@ -8811,15 +8905,19 @@
                         break;
 
                 }
-
                 infos[i] = new UiccSlotInfo(
-                        slot.isActive(),
                         slot.isEuicc(),
                         cardId,
                         cardState,
-                        slot.getPhoneId(),
                         slot.isExtendedApduSupported(),
-                        slot.isRemovable());
+                        slot.isRemovable(), Collections.singletonList(
+                        new UiccPortInfo(
+                                iccId,
+                                0 /* TODO: to use portList from UiccSlots */,
+                                slot.getPhoneId(),
+                                slot.isActive())));
+                //setting the value after compatibility check
+                infos[i].setLogicalSlotAccessRestricted(isLogicalSlotAccessRestricted);
             }
             return infos;
         } finally {
@@ -8828,6 +8926,8 @@
     }
 
     @Override
+    @Deprecated
+    //TODO : once integrating with HAL Changes we can clean up this Internal API.
     public boolean switchSlots(int[] physicalSlots) {
         enforceModifyPermission();
 
@@ -8840,6 +8940,24 @@
     }
 
     @Override
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean setSimSlotMapping(@NonNull List<UiccSlotMapping> slotMapping) {
+        enforceModifyPermission();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            //TODO: once integrating the HAL changes we can proceed with to work on the parsing side
+            int[] physicalSlots = new int[slotMapping.size()];
+            for (int i = 0; i < physicalSlots.length; i++) {
+                physicalSlots[i] = slotMapping.get(i).getPhysicalSlotIndex();
+            }
+            return (Boolean) sendRequest(CMD_SWITCH_SLOTS, physicalSlots);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     public int getCardIdForDefaultEuicc(int subId, String callingPackage) {
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -9422,7 +9540,7 @@
     }
 
     @Override
-    public int[] getSlotsMapping() {
+    public int[] getSlotsMapping(@NonNull String callingPackage) {
         enforceReadPrivilegedPermission("getSlotsMapping");
 
         final long identity = Binder.clearCallingIdentity();
@@ -9430,7 +9548,7 @@
             int phoneCount = TelephonyManager.getDefault().getPhoneCount();
             // All logical slots should have a mapping to a physical slot.
             int[] logicalSlotsMapping = new int[phoneCount];
-            UiccSlotInfo[] slotInfos = getUiccSlotsInfo();
+            UiccSlotInfo[] slotInfos = getUiccSlotsInfo(callingPackage);
             for (int i = 0; i < slotInfos.length; i++) {
                 if (SubscriptionManager.isValidPhoneId(slotInfos[i].getLogicalSlotIdx())) {
                     logicalSlotsMapping[slotInfos[i].getLogicalSlotIdx()] = i;
@@ -10927,7 +11045,8 @@
      * Register an IMS connection state callback
      */
     @Override
-    public void registerImsStateCallback(int subId, int feature, IImsStateCallback cb) {
+    public void registerImsStateCallback(int subId, int feature, IImsStateCallback cb,
+            String callingPackage) {
         if (feature == ImsFeature.FEATURE_MMTEL) {
             // ImsMmTelManager
             // The following also checks READ_PRIVILEGED_PHONE_STATE.
@@ -10959,10 +11078,14 @@
                     "IMS not available on device.");
         }
 
+        if (callingPackage == null) {
+            callingPackage = getCurrentPackageName();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             int slotId = getSlotIndexOrException(subId);
-            controller.registerImsStateCallback(subId, feature, cb);
+            controller.registerImsStateCallback(subId, feature, cb, callingPackage);
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index fc4fce7..17adef3 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -17,6 +17,7 @@
 package com.android.phone.settings;
 
 import static android.net.ConnectivityManager.NetworkCallback;
+
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
 import android.content.ComponentName;
@@ -57,7 +58,6 @@
 import android.telephony.CellSignalStrengthLte;
 import android.telephony.CellSignalStrengthWcdma;
 import android.telephony.DataSpecificRegistrationInfo;
-import android.telephony.data.NetworkSlicingConfig;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.RadioAccessFamily;
@@ -66,6 +66,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
+import android.telephony.data.NetworkSlicingConfig;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Menu;
@@ -102,8 +103,8 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeoutException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Radio Information Class
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/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/ImsStateCallbackControllerTest.java b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
index 75690bb..c493f6b 100644
--- a/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
+++ b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
@@ -195,7 +195,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -211,7 +211,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -237,7 +237,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -258,7 +258,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -284,7 +284,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -300,7 +300,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -330,7 +330,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -383,7 +383,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -413,7 +413,7 @@
         createController(1);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback0, "callback0");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         verify(mCallback0, times(1)).onUnavailable(REASON_IMS_SERVICE_DISCONNECTED);
@@ -443,9 +443,9 @@
         createController(2);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0, "callback0");
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_RCS, mCallback1);
+                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_RCS, mCallback1, "callback1");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         assertTrue(mImsStateCallbackController.isRegistered(mCallback1));
@@ -473,11 +473,11 @@
                 .thenReturn(false);
 
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0, "callback0");
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_MMTEL, mCallback1);
+                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_MMTEL, mCallback1, "callback1");
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_RCS, mCallback2);
+                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_RCS, mCallback2, "callback2");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         assertTrue(mImsStateCallbackController.isRegistered(mCallback1));
@@ -609,13 +609,13 @@
 
         // registration
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_MMTEL, mCallback0, "callback0");
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback1);
+                .registerImsStateCallback(SLOT_0_SUB_ID, FEATURE_RCS, mCallback1, "callback1");
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_MMTEL, mCallback2);
+                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_MMTEL, mCallback2, "callback2");
         mImsStateCallbackController
-                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_RCS, mCallback3);
+                .registerImsStateCallback(SLOT_1_SUB_ID, FEATURE_RCS, mCallback3, "callback3");
         processAllMessages();
         assertTrue(mImsStateCallbackController.isRegistered(mCallback0));
         assertTrue(mImsStateCallbackController.isRegistered(mCallback1));
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);
     }
 }