Merge "Add interface for CTS test to ignore cellular service state" into main
diff --git a/flags/data.aconfig b/flags/data.aconfig
index 0fd094d..ccd5db4 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -132,3 +132,10 @@
   }
 }
 
+# OWNER=TBD TARGET=TBD
+flag {
+  name: "oem_paid_private"
+  namespace: "telephony"
+  description: "Support OEM_PAID and OEM_PRIVATE networks"
+  bug: "366194627"
+}
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 0ebaeba..860c864 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -217,3 +217,15 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+# OWNER=jackyu TARGET=25Q2
+flag {
+    name: "hsum_package_manager"
+    namespace: "telephony"
+    description: "Fixed the bug that package manager is not for the right user"
+    bug:"356827794"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
index 55baecc..4f9d84d 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.annotation.NonNull;
+import android.app.ActivityManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -161,7 +162,11 @@
     };
 
     public CarrierServiceBindHelper(Context context) {
-        mContext = context.createContextAsUser(Process.myUserHandle(), 0);
+        mContext =
+                context.createContextAsUser(
+                        Flags.supportCarrierServicesForHsum()
+                        ? UserHandle.of(ActivityManager.getCurrentUser())
+                        : Process.myUserHandle(), 0);
 
         updateBindingsAndSimStates();
 
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index c7c05bc..ca03f5d 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -75,6 +75,7 @@
 import com.android.internal.telephony.analytics.TelephonyAnalytics;
 import com.android.internal.telephony.analytics.TelephonyAnalytics.SmsMmsAnalytics;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteSessionStats;
 import com.android.internal.telephony.util.NotificationChannelController;
@@ -2153,10 +2154,13 @@
                 // TODO(b/355049884): This is looking at sms package of the wrong user!
                 UserManager userManager =
                         (UserManager) context.getSystemService(Context.USER_SERVICE);
+                PackageManager pm = context.getPackageManager();
+                if (Flags.hsumPackageManager()) {
+                    pm = context.createContextAsUser(UserHandle.CURRENT, 0).getPackageManager();
+                }
                 if (userManager.isUserUnlocked()) {
-                    context.startActivityAsUser(context.getPackageManager()
-                            .getLaunchIntentForPackage(Telephony.Sms.getDefaultSmsPackage(context)),
-                            UserHandle.CURRENT);
+                    context.startActivityAsUser(pm.getLaunchIntentForPackage(
+                            Telephony.Sms.getDefaultSmsPackage(context)), UserHandle.CURRENT);
                 }
             }
         }
diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
index 073e242..7ee3de2 100644
--- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java
+++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
@@ -785,9 +785,16 @@
      */
     @Nullable
     private String getCurrentPackageName() {
+        if (mFeatureFlags.hsumPackageManager()) {
+            PackageManager pm = mContext.createContextAsUser(Binder.getCallingUserHandle(), 0)
+                    .getPackageManager();
+            if (pm == null) return null;
+            String[] callingPackageNames = pm.getPackagesForUid(Binder.getCallingUid());
+            return (callingPackageNames == null) ? null : callingPackageNames[0];
+        }
         if (mPackageManager == null) return null;
-        String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid());
-        return (callingUids == null) ? null : callingUids[0];
+        String[] callingPackageNames = mPackageManager.getPackagesForUid(Binder.getCallingUid());
+        return (callingPackageNames == null) ? null : callingPackageNames[0];
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java
index 1295f38..e3c409d 100644
--- a/src/java/com/android/internal/telephony/SmsController.java
+++ b/src/java/com/android/internal/telephony/SmsController.java
@@ -224,7 +224,15 @@
         }
     }
 
+    @NonNull
     private String getCallingPackage() {
+        if (mFlags.hsumPackageManager()) {
+            PackageManager pm = mContext.createContextAsUser(Binder.getCallingUserHandle(), 0)
+                    .getPackageManager();
+            String[] packages = pm.getPackagesForUid(Binder.getCallingUid());
+            if (packages == null || packages.length == 0) return "";
+            return packages[0];
+        }
         return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid())[0];
     }
 
@@ -412,9 +420,7 @@
             boolean persistMessageForNonDefaultSmsApp, long messageId) {
         // This is different from the checking of other method. It prefers the package name
         // returned by getCallPackage() for backward-compatibility.
-        if (getCallingPackage() != null) {
-            callingPackage = getCallingPackage();
-        }
+        callingPackage = getCallingPackage();
         UserHandle callingUser = Binder.getCallingUserHandle();
 
         Rlog.d(LOG_TAG, "sendMultipartTextForSubscriber caller=" + callingPackage);
diff --git a/src/java/com/android/internal/telephony/data/DataUtils.java b/src/java/com/android/internal/telephony/data/DataUtils.java
index 20da97f..c88e0b3 100644
--- a/src/java/com/android/internal/telephony/data/DataUtils.java
+++ b/src/java/com/android/internal/telephony/data/DataUtils.java
@@ -287,6 +287,8 @@
             case NetworkCapabilities.NET_CAPABILITY_VSIM -> ApnSetting.TYPE_VSIM;
             case NetworkCapabilities.NET_CAPABILITY_BIP -> ApnSetting.TYPE_BIP;
             case NetworkCapabilities.NET_CAPABILITY_RCS -> ApnSetting.TYPE_RCS;
+            case NetworkCapabilities.NET_CAPABILITY_OEM_PAID -> ApnSetting.TYPE_OEM_PAID;
+            case NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE -> ApnSetting.TYPE_OEM_PRIVATE;
             default -> ApnSetting.TYPE_NONE;
         };
     }
@@ -315,6 +317,8 @@
             case ApnSetting.TYPE_VSIM -> NetworkCapabilities.NET_CAPABILITY_VSIM;
             case ApnSetting.TYPE_ENTERPRISE -> NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
             case ApnSetting.TYPE_RCS -> NetworkCapabilities.NET_CAPABILITY_RCS;
+            case ApnSetting.TYPE_OEM_PAID -> NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+            case ApnSetting.TYPE_OEM_PRIVATE -> NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
             default -> -1;
         };
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 51bd7df..c89aa65 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -62,6 +62,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.StatusBarManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -126,6 +127,7 @@
 import android.telephony.satellite.SatelliteSubscriberInfo;
 import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
 import android.telephony.satellite.SatelliteSubscriptionInfo;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
@@ -566,6 +568,11 @@
     private String mConfigSatelliteGatewayServicePackage = "";
     private String mConfigSatelliteCarrierRoamingEsosProvisionedClass = "";
 
+    private boolean mIsNotificationShowing = false;
+    private static final String OPEN_MESSAGE_BUTTON = "open_message_button";
+    private static final String HOW_IT_WORKS_BUTTON = "how_it_works_button";
+    private static final String ACTION_NOTIFICATION_CLICK = "action_notification_click";
+    private static final String ACTION_NOTIFICATION_DISMISS = "action_notification_dismiss";
     private BroadcastReceiver
             mDefaultSmsSubscriptionChangedBroadcastReceiver = new BroadcastReceiver() {
                 @Override
@@ -5164,14 +5171,18 @@
         for (Phone phone : PhoneFactory.getPhones()) {
             int subId = phone.getSubId();
             ServiceState serviceState = phone.getServiceState();
-            if (serviceState == null) {
+            if (serviceState == null || subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                 continue;
             }
 
             synchronized (mSatelliteConnectedLock) {
                 CarrierRoamingSatelliteSessionStats sessionStats =
                         mCarrierRoamingSatelliteSessionStatsMap.get(subId);
-
+                if (DEBUG) {
+                    plogd("handleServiceStateForSatelliteConnectionViaCarrier : SubId = " + subId
+                            + "  isUsingNonTerrestrialNetwork = "
+                            + serviceState.isUsingNonTerrestrialNetwork());
+                }
                 if (serviceState.isUsingNonTerrestrialNetwork()) {
                     if (sessionStats != null) {
                         sessionStats.onSignalStrength(phone);
@@ -5223,7 +5234,6 @@
 
     private void updateLastNotifiedNtnModeAndNotify(@Nullable Phone phone) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
-
         if (phone == null) {
             return;
         }
@@ -5238,6 +5248,9 @@
                 mLastNotifiedNtnMode.put(subId, currNtnMode);
                 phone.notifyCarrierRoamingNtnModeChanged(currNtnMode);
                 logCarrierRoamingSatelliteSessionStats(phone, lastNotifiedNtnMode, currNtnMode);
+                if(mIsNotificationShowing && !currNtnMode) {
+                    dismissSatelliteNotification();
+                }
             }
         }
     }
@@ -5685,29 +5698,31 @@
         }
 
         Pair<Boolean, Integer> isNtn = isUsingNonTerrestrialNetworkViaCarrier();
+        boolean notificationKeyStatus = mSharedPreferences.getBoolean(
+                SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false);
+        if (DEBUG) {
+            logd("determineAutoConnectSystemNotification: isNtn.first = " + isNtn.first
+                    + " IsNotiToShow = " + !notificationKeyStatus + " mIsNotificationShowing = "
+                    + mIsNotificationShowing);
+        }
         if (isNtn.first) {
-            if (mSharedPreferences == null) {
-                try {
-                    mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF,
-                            Context.MODE_PRIVATE);
-                } catch (Exception e) {
-                    loge("Cannot get default shared preferences: " + e);
-                }
-            }
-            if (mSharedPreferences == null) {
-                loge("determineSystemNotification: Cannot get default shared preferences");
-                return;
-            }
-            if (!mSharedPreferences.getBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false)) {
+            if (!notificationKeyStatus) {
                 updateSatelliteSystemNotification(isNtn.second,
                         CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC,
                         /*visible*/ true);
-                mSharedPreferences.edit().putBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY,
-                        true).apply();
             }
+        } else if (mIsNotificationShowing
+                && !isSatelliteConnectedViaCarrierWithinHysteresisTime()) {
+            // Dismiss the notification if it is still displaying.
+            dismissSatelliteNotification();
         }
     }
 
+    private void dismissSatelliteNotification() {
+        mIsNotificationShowing = false;
+        updateSatelliteSystemNotification(-1, -1,/*visible*/ false);
+    }
+
     /**
      * Update the system notification to reflect the current satellite status, that's either already
      * connected OR needs to be manually enabled. The device should only display one notification
@@ -5721,15 +5736,13 @@
      */
     private void updateSatelliteSystemNotification(int subId,
             @CARRIER_ROAMING_NTN_CONNECT_TYPE int carrierRoamingNtnConnectType, boolean visible) {
-        plogd("updateSatelliteSystemNotification subId=" + subId
-                + ", carrierRoamingNtnConnectType=" + SatelliteServiceUtils
-                .carrierRoamingNtnConnectTypeToString(carrierRoamingNtnConnectType)
-                + ", visible=" + visible);
+        plogd("updateSatelliteSystemNotification subId=" + subId + ", carrierRoamingNtnConnectType="
+                + SatelliteServiceUtils.carrierRoamingNtnConnectTypeToString(
+                carrierRoamingNtnConnectType) + ", visible=" + visible);
         final NotificationChannel notificationChannel = new NotificationChannel(
                 NOTIFICATION_CHANNEL_ID,
                 NOTIFICATION_CHANNEL,
-                NotificationManager.IMPORTANCE_DEFAULT
-        );
+                NotificationManager.IMPORTANCE_DEFAULT);
         notificationChannel.setSound(null, null);
         NotificationManager notificationManager = mContext.getSystemService(
                 NotificationManager.class);
@@ -5762,54 +5775,130 @@
                         com.android.internal.R.color.system_notification_accent_color))
                 .setVisibility(Notification.VISIBILITY_PUBLIC);
 
-        // Add action to invoke message application.
-        // getDefaultSmsPackage and getLaunchIntentForPackage are nullable.
-        Optional<Intent> nullableIntent = Optional.ofNullable(
-                        Telephony.Sms.getDefaultSmsPackage(mContext))
-                .flatMap(packageName -> {
-                    PackageManager pm = mContext.getPackageManager();
-                    return Optional.ofNullable(pm.getLaunchIntentForPackage(packageName));
-                });
-        // If nullableIntent is null, create new Intent for most common way to invoke message app.
-        Intent finalIntent = nullableIntent.map(intent -> {
-            // Invoke the home screen of default message application.
-            intent.setAction(Intent.ACTION_MAIN);
-            intent.addCategory(Intent.CATEGORY_HOME);
-            return intent;
-        }).orElseGet(() -> {
-            ploge("showSatelliteSystemNotification: no default sms package name, Invoke "
-                    + "default sms compose window instead");
-            Intent newIntent = new Intent(Intent.ACTION_VIEW);
-            newIntent.setData(Uri.parse("sms:"));
-            return newIntent;
-        });
-
-        PendingIntent pendingIntentOpenMessage = PendingIntent.getActivity(mContext, 0,
-                finalIntent, PendingIntent.FLAG_IMMUTABLE);
+        // Intent for `Open Messages` [Button 1]
+        Intent openMessageIntent = new Intent();
+        openMessageIntent.setAction(OPEN_MESSAGE_BUTTON);
+        PendingIntent openMessagePendingIntent = PendingIntent.getBroadcast(mContext, 0,
+                openMessageIntent, PendingIntent.FLAG_IMMUTABLE);
         Notification.Action actionOpenMessage = new Notification.Action.Builder(0,
                 mContext.getResources().getString(R.string.satellite_notification_open_message),
-                pendingIntentOpenMessage).build();
-        notificationBuilder.addAction(actionOpenMessage);
+                openMessagePendingIntent).build();
+        notificationBuilder.addAction(actionOpenMessage);   // Handle `Open Messages` button
 
-        // Add action to invoke Satellite setting activity in Settings.
-        Intent intentSatelliteSetting = new Intent(ACTION_SATELLITE_SETTING);
-        intentSatelliteSetting.putExtra("sub_id", subId);
-        PendingIntent pendingIntentSatelliteSetting = PendingIntent.getActivity(mContext, 0,
-                intentSatelliteSetting, PendingIntent.FLAG_IMMUTABLE);
-
-        Notification.Action actionOpenSatelliteSetting = new Notification.Action.Builder(null,
+        // Button for `How it works` [Button 2]
+        Intent howItWorksIntent = new Intent();
+        howItWorksIntent.setAction(HOW_IT_WORKS_BUTTON);
+        howItWorksIntent.putExtra("SUBID", subId);
+        PendingIntent howItWorksPendingIntent = PendingIntent.getBroadcast(mContext, 0,
+                howItWorksIntent, PendingIntent.FLAG_IMMUTABLE);
+        Notification.Action actionHowItWorks = new Notification.Action.Builder(0,
                 mContext.getResources().getString(R.string.satellite_notification_how_it_works),
-                pendingIntentSatelliteSetting).build();
-        notificationBuilder.addAction(actionOpenSatelliteSetting);
+                howItWorksPendingIntent).build();
+        notificationBuilder.addAction(actionHowItWorks);    // Handle `How it works` button
+
+        // Intent for clicking the main notification body
+        Intent notificationClickIntent = new Intent(ACTION_NOTIFICATION_CLICK);
+        PendingIntent notificationClickPendingIntent = PendingIntent.getBroadcast(mContext, 0,
+                notificationClickIntent, PendingIntent.FLAG_IMMUTABLE);
+        notificationBuilder.setContentIntent(
+                notificationClickPendingIntent); // Handle notification body click
+
+        // Intent for dismissing/swiping the notification
+        Intent deleteIntent = new Intent(ACTION_NOTIFICATION_DISMISS);
+        PendingIntent deletePendingIntent = PendingIntent.getBroadcast(mContext, 0, deleteIntent,
+                PendingIntent.FLAG_IMMUTABLE);
+        notificationBuilder.setDeleteIntent(
+                deletePendingIntent);  // Handle notification swipe/dismiss
 
         notificationManager.notifyAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
                 notificationBuilder.build(), UserHandle.ALL);
 
+        // The Intent filter is to receive the above four events.
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(OPEN_MESSAGE_BUTTON);
+        filter.addAction(HOW_IT_WORKS_BUTTON);
+        filter.addAction(ACTION_NOTIFICATION_CLICK);
+        filter.addAction(ACTION_NOTIFICATION_DISMISS);
+        mContext.registerReceiver(mNotificationInteractionBroadcastReceiver, filter,
+                Context.RECEIVER_EXPORTED);
+
+        mIsNotificationShowing = true;
         mCarrierRoamingSatelliteControllerStats.reportCountOfSatelliteNotificationDisplayed();
         mCarrierRoamingSatelliteControllerStats.reportCarrierId(getSatelliteCarrierId());
         mSessionMetricsStats.addCountOfSatelliteNotificationDisplayed();
     }
 
+    private final BroadcastReceiver mNotificationInteractionBroadcastReceiver =
+            new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent receivedIntent) {
+                    String intentAction = receivedIntent.getAction();
+                    if (TextUtils.isEmpty(intentAction)) {
+                        loge("Received empty action from the notification");
+                        return;
+                    }
+                    if (DBG) {
+                        plogd("Notification Broadcast recvd action = "
+                                + receivedIntent.getAction());
+                    }
+                    boolean closeStatusBar = true;
+                    switch (intentAction) {
+                        case OPEN_MESSAGE_BUTTON -> {
+                            // Add action to invoke message application.
+                            // getDefaultSmsPackage and getLaunchIntentForPackage are nullable.
+                            Optional<Intent> nullableIntent = Optional.ofNullable(
+                                    Telephony.Sms.getDefaultSmsPackage(context)).flatMap(
+                                    packageName -> {
+                                        PackageManager pm = context.getPackageManager();
+                                        return Optional.ofNullable(
+                                                pm.getLaunchIntentForPackage(packageName));
+                                    });
+                            // If nullableIntent is null, create new Intent for most common way to
+                            // invoke
+                            // message app.
+                            Intent finalIntent = nullableIntent.map(intent -> {
+                                // Invoke the home screen of default message application.
+                                intent.setAction(Intent.ACTION_MAIN);
+                                intent.addCategory(Intent.CATEGORY_HOME);
+                                return intent;
+                            }).orElseGet(() -> {
+                                ploge("showSatelliteSystemNotification: no default sms package "
+                                        + "name, Invoke default sms compose window instead");
+                                Intent newIntent = new Intent(Intent.ACTION_VIEW);
+                                newIntent.setData(Uri.parse("sms:"));
+                                return newIntent;
+                            });
+                            context.startActivity(finalIntent);
+                        }
+                        case HOW_IT_WORKS_BUTTON -> {
+                            int subId = receivedIntent.getIntExtra("SUBID", -1);
+                            Intent intentSatelliteSetting = new Intent(ACTION_SATELLITE_SETTING);
+                            intentSatelliteSetting.putExtra("sub_id", subId);
+                            intentSatelliteSetting.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                            context.startActivity(intentSatelliteSetting);
+
+                        }
+                        case ACTION_NOTIFICATION_DISMISS -> closeStatusBar = false;
+                    }
+                    // Note : ACTION_NOTIFICATION_DISMISS is not required to handled
+                    dismissNotificationAndUpdatePref(closeStatusBar);
+                }
+            };
+
+    private void dismissNotificationAndUpdatePref(boolean closeStatusBar) {
+        dismissSatelliteNotification();
+        if (closeStatusBar) {
+            // Collapse the status bar once user interact with notification.
+            StatusBarManager statusBarManager = mContext.getSystemService(StatusBarManager.class);
+            if (statusBarManager != null) {
+                statusBarManager.collapsePanels();
+            }
+        }
+        // update the sharedpref only when user interacted with the notification.
+        mSharedPreferences.edit().putBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, true).apply();
+        mContext.unregisterReceiver(mNotificationInteractionBroadcastReceiver);
+    }
+
     private void resetCarrierRoamingSatelliteModeParams() {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
 
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index d42a410..23dcefc 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -124,6 +124,8 @@
 
     @Nullable private PersistentLogger mPersistentLogger = null;
 
+    private boolean mIsTestEmergencyNumber = false;
+
     /**
      * Create an instance of SatelliteSOSMessageRecommender.
      *
@@ -213,11 +215,13 @@
      * @param connection The connection created by TelephonyConnectionService for the emergency
      *                   call.
      */
-    public void onEmergencyCallStarted(@NonNull Connection connection) {
+    public void onEmergencyCallStarted(@NonNull Connection connection,
+            boolean isTestEmergencyNumber) {
         if (!isSatelliteSupported()) {
             plogd("onEmergencyCallStarted: satellite is not supported");
             return;
         }
+        mIsTestEmergencyNumber = isTestEmergencyNumber;
 
         if (hasMessages(EVENT_EMERGENCY_CALL_STARTED)) {
             logd("onEmergencyCallStarted: Ignoring due to ongoing event:");
@@ -259,6 +263,7 @@
     }
 
     private void handleEmergencyCallStartedEvent(@NonNull Connection connection) {
+        plogd("handleEmergencyCallStartedEvent: connection=" + connection);
         mSatelliteController.setLastEmergencyCallTime();
 
         if (sendEventDisplayEmergencyMessageForcefully(connection)) {
@@ -280,7 +285,7 @@
 
     private void handleSatelliteProvisionStateChangedEvent(boolean provisioned) {
         if (!provisioned) {
-            cleanUpResources();
+            cleanUpResources(false);
         }
     }
 
@@ -320,7 +325,8 @@
                     || isSatelliteConnectedViaCarrierWithinHysteresisTime())
                     && shouldTrackCall(mEmergencyConnection.getState())) {
                 plogd("handleTimeoutEvent: Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer");
-                Bundle extras = createExtraBundleForEventDisplayEmergencyMessage();
+                Bundle extras = createExtraBundleForEventDisplayEmergencyMessage(
+                        mIsTestEmergencyNumber);
                 mEmergencyConnection.sendConnectionEvent(
                         TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras);
                 isDialerNotified = true;
@@ -330,8 +336,7 @@
                     + ", isCellularAvailable=" + isCellularAvailable
                     + ", isSatelliteAllowed=" + isSatelliteAllowed()
                     + ", shouldTrackCall=" + shouldTrackCall(mEmergencyConnection.getState()));
-            reportESosRecommenderDecision(isDialerNotified);
-            cleanUpResources();
+            cleanUpResources(isDialerNotified);
         }
     }
 
@@ -382,13 +387,12 @@
              * we're not tracking. There must be some unexpected things happened in
              * TelephonyConnectionService. Thus, we need to clean up the resources.
              */
-            cleanUpResources();
+            cleanUpResources(false);
             return;
         }
 
         if (!shouldTrackCall(state)) {
-            reportESosRecommenderDecision(false);
-            cleanUpResources();
+            cleanUpResources(false);
         } else {
             // Location service will enter emergency mode only when connection state changes to
             // STATE_DIALING
@@ -399,7 +403,8 @@
         }
     }
 
-    private void reportESosRecommenderDecision(boolean isDialerNotified) {
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    protected void reportESosRecommenderDecision(boolean isDialerNotified) {
         SatelliteStats.getInstance().onSatelliteSosMessageRecommender(
                 new SatelliteStats.SatelliteSosMessageRecommenderParams.Builder()
                         .setDisplaySosMessageSent(isDialerNotified)
@@ -413,7 +418,9 @@
                         .setCarrierId(getAvailableNtnCarrierID()).build());
     }
 
-    private void cleanUpResources() {
+    private void cleanUpResources(boolean isDialerNotified) {
+        plogd("cleanUpResources");
+        reportESosRecommenderDecision(isDialerNotified);
         synchronized (mLock) {
             stopTimer();
             if (mEmergencyConnection != null) {
@@ -424,6 +431,7 @@
             mIsTimerTimedOut = false;
             mCheckingAccessRestrictionInProgress = false;
             mIsSatelliteAllowedForCurrentLocation = false;
+            mIsTestEmergencyNumber = false;
         }
     }
 
@@ -501,7 +509,8 @@
         if (!SatelliteServiceUtils.isCellularAvailable() && mEmergencyConnection != null) {
             startTimer();
         } else {
-            logv("handleStateChangedEventForHysteresisTimer stopTimer");
+            plogd("handleStateChangedEventForHysteresisTimer stopTimer, mEmergencyConnection="
+                    + mEmergencyConnection);
             stopTimer();
         }
     }
@@ -514,7 +523,7 @@
             sendMessageDelayed(obtainMessage(EVENT_TIME_OUT), mTimeoutMillis);
             mCountOfTimerStarted++;
             mIsTimerTimedOut = false;
-            logd("startTimer mCountOfTimerStarted=" + mCountOfTimerStarted);
+            plogd("startTimer mCountOfTimerStarted=" + mCountOfTimerStarted);
         }
     }
 
@@ -582,11 +591,13 @@
 
     @Nullable
     private static String getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(
-            @NonNull Context context) {
+            @NonNull Context context, boolean isTestEmergencyNumber) {
         String action;
         try {
-            action = context.getResources().getString(
-                    R.string.config_satellite_emergency_handover_intent_action);
+            int actionIntent = isTestEmergencyNumber
+                    ? R.string.config_satellite_test_with_esp_replies_intent_action
+                    : R.string.config_satellite_emergency_handover_intent_action;
+            action = context.getResources().getString(actionIntent);
         } catch (Resources.NotFoundException ex) {
             loge("getSatelliteEmergencyHandoverIntentFilterActionFromOverlayConfig: ex=" + ex);
             action = null;
@@ -632,13 +643,15 @@
         return callback;
     }
 
-    @NonNull private Bundle createExtraBundleForEventDisplayEmergencyMessage() {
+    @NonNull private Bundle createExtraBundleForEventDisplayEmergencyMessage(
+            boolean isTestEmergencyNumber) {
         int handoverType = EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
         Pair<String, String> oemSatelliteMessagingApp =
                 getOemEnabledSatelliteHandoverAppFromOverlayConfig(mContext);
         String packageName = oemSatelliteMessagingApp.first;
         String className = oemSatelliteMessagingApp.second;
-        String action = getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(mContext);
+        String action = getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(mContext,
+                isTestEmergencyNumber);
 
         if (isSatelliteConnectedViaCarrierWithinHysteresisTime()
                 || isEmergencyCallToSatelliteHandoverTypeT911Enforced()) {
@@ -707,7 +720,8 @@
             @NonNull Connection connection) {
         plogd("Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer forcefully.");
         mEmergencyConnection = connection;
-        Bundle extras = createExtraBundleForEventDisplayEmergencyMessage();
+        Bundle extras = createExtraBundleForEventDisplayEmergencyMessage(
+                /* isTestEmergencyNumber= */ true);
         connection.sendConnectionEvent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras);
         mEmergencyConnection = null;
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index 21c5c44..3936a7e 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -481,12 +481,12 @@
                 if ((state == STATE_IN_SERVICE || state == STATE_EMERGENCY_ONLY
                         || serviceState.isEmergencyOnly())
                         && !isSatellitePlmn(phone.getSubId(), serviceState)) {
-                    logv("isCellularAvailable true");
+                    logd("isCellularAvailable true");
                     return true;
                 }
             }
         }
-        logv("isCellularAvailable false");
+        logd("isCellularAvailable false");
         return false;
     }
 
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 87d6d27..353493b 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -4561,6 +4561,10 @@
             // Too many packages running with phone uid. Just return one here.
             return "com.android.phone";
         }
+        if (mFeatureFlags.hsumPackageManager()) {
+            return Arrays.toString(mContext.createContextAsUser(Binder.getCallingUserHandle(), 0)
+                    .getPackageManager().getPackagesForUid(Binder.getCallingUid()));
+        }
         return Arrays.toString(mContext.getPackageManager().getPackagesForUid(
                 Binder.getCallingUid()));
     }
@@ -4765,9 +4769,16 @@
      */
     @Nullable
     private String getCurrentPackageName() {
+        if (mFeatureFlags.hsumPackageManager()) {
+            PackageManager pm = mContext.createContextAsUser(Binder.getCallingUserHandle(), 0)
+                    .getPackageManager();
+            if (pm == null) return null;
+            String[] callingPackageNames = pm.getPackagesForUid(Binder.getCallingUid());
+            return (callingPackageNames == null) ? null : callingPackageNames[0];
+        }
         if (mPackageManager == null) return null;
-        String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid());
-        return (callingUids == null) ? null : callingUids[0];
+        String[] callingPackageNames = mPackageManager.getPackagesForUid(Binder.getCallingUid());
+        return (callingPackageNames == null) ? null : callingPackageNames[0];
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java
index 7bdec47..3bd66f8 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java
@@ -133,8 +133,7 @@
             UiccCard card, MultipleEnabledProfilesMode supportedMepMode) {
         super(c, ci, ics, phoneId, lock, card);
         // TODO: Set supportExtendedApdu based on ATR.
-        mApduSender = new ApduSender(c, phoneId, ci, ISD_R_AID,
-                              false /* supportExtendedApdu */);
+        mApduSender = new ApduSender(ci, ISD_R_AID, false /* supportExtendedApdu */);
         if (TextUtils.isEmpty(ics.eid)) {
             loge("no eid given in constructor for phone " + phoneId);
         } else {
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
index b17a0fd..0a56b2b 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
@@ -17,17 +17,11 @@
 package com.android.internal.telephony.uicc.euicc.apdu;
 
 import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
-import android.preference.PreferenceManager;
 import android.telephony.IccOpenLogicalChannelResponse;
-import android.util.Base64;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.euicc.EuiccSession;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback;
 import com.android.internal.telephony.uicc.euicc.async.AsyncResultHelper;
@@ -42,14 +36,7 @@
  * before sending and closed after all APDU commands are sent. The complete response of the last
  * APDU command will be returned. If any APDU command returns an error status (other than
  * {@link #STATUS_NO_ERROR}) or causing an exception, an {@link ApduException} will be returned
- * immediately without sending the rest of commands.
- *
- * <p>If {@link EuiccSession} indicates ongoing session(s), the behavior changes: 1) before
- * sending, check if a channel is opened already. If yes, reuse the channel and send APDU commands
- * directly. If no, open a channel before sending. 2) The channel is closed when EuiccSession
- * class ends all sessions, independent of APDU sending.
- *
- * <p>This class is thread-safe.
+ * immediately without sending the rest of commands. This class is thread-safe.
  *
  * @hide
  */
@@ -63,12 +50,8 @@
     // Status code of APDU response
     private static final int STATUS_NO_ERROR = 0x9000;
     private static final int SW1_NO_ERROR = 0x91;
-    private static final int STATUS_CHANNEL_CLOSED = 0x6881; // b/359336875
 
     private static final int WAIT_TIME_MS = 2000;
-    private static final String CHANNEL_ID_PRE = "esim-channel";
-    static final String ISD_R_AID = "A0000005591010FFFFFFFF8900000100";
-    private static final String CHANNEL_RESPONSE_ID_PRE = "esim-res-id";
 
     private static void logv(String msg) {
         Rlog.v(LOG_TAG, msg);
@@ -78,50 +61,26 @@
         Rlog.d(LOG_TAG, msg);
     }
 
-    private static void loge(String msg) {
-        Rlog.e(LOG_TAG, msg);
-    }
-
     private final String mAid;
     private final boolean mSupportExtendedApdu;
     private final OpenLogicalChannelInvocation mOpenChannel;
     private final CloseLogicalChannelInvocation mCloseChannel;
     private final TransmitApduLogicalChannelInvocation mTransmitApdu;
-    private final Context mContext;
-    private final String mChannelKey;
-    private final String mChannelResponseKey;
-    // closeAnyOpenChannel() needs a handler for its async callbacks.
-    private final Handler mHandler;
 
-    // Lock for accessing mChannelInUse. We only allow to open a single logical
-    // channel at any time for an AID and to invoke one command at any time.
-    // Only the thread (and its async callbacks) that sets mChannelInUse
-    // can open/close/send, and update mChannelOpened.
-    private final Object mChannelInUseLock = new Object();
-    @GuardedBy("mChannelInUseLock")
-    private boolean mChannelInUse;
+    // Lock for accessing mChannelOpened. We only allow to open a single logical channel at any
+    // time for an AID.
+    private final Object mChannelLock = new Object();
     private boolean mChannelOpened;
 
     /**
      * @param aid The AID that will be used to open a logical channel to.
      */
-    public ApduSender(Context context, int phoneId, CommandsInterface ci, String aid,
-            boolean supportExtendedApdu) {
-        if (!aid.equals(ISD_R_AID) && !"user".equals(Build.TYPE)) {
-            throw new IllegalArgumentException("Only ISD-R AID is supported.");
-        }
+    public ApduSender(CommandsInterface ci, String aid, boolean supportExtendedApdu) {
         mAid = aid;
-        mContext = context;
         mSupportExtendedApdu = supportExtendedApdu;
         mOpenChannel = new OpenLogicalChannelInvocation(ci);
         mCloseChannel = new CloseLogicalChannelInvocation(ci);
         mTransmitApdu = new TransmitApduLogicalChannelInvocation(ci);
-        mChannelKey = CHANNEL_ID_PRE + "_" + phoneId;
-        mChannelResponseKey = CHANNEL_RESPONSE_ID_PRE + "_" + phoneId;
-        mHandler = new Handler();
-
-        mChannelInUse = false;
-        closeAnyOpenChannel();
     }
 
     /**
@@ -140,125 +99,79 @@
             RequestProvider requestProvider,
             ApduSenderResultCallback resultCallback,
             Handler handler) {
-        if (!acquireChannelLock()) {
-            AsyncResultHelper.throwException(
-                    new ApduException("The logical channel is still in use."),
-                    resultCallback,
-                    handler);
-            return;
-        }
-
-        boolean euiccSession = EuiccSession.get().hasSession();
-        // Case 1, channel was already opened AND EuiccSession is ongoing.
-        // sendCommand directly. Do not immediately close channel after sendCommand.
-        // Case 2, channel was already opened AND EuiccSession is not ongoing. This means
-        // EuiccSession#endSession is already called but closeAnyOpenChannel() is not
-        // yet executed because of waiting to acquire lock hold by this thread.
-        // sendCommand directly. Close channel immediately anyways after sendCommand.
-        // Case 3, channel is not open AND EuiccSession is ongoing. Open channel
-        // before sendCommand. Do not immediately close channel after sendCommand.
-        // Case 4, channel is not open AND EuiccSession is not ongoing. Open channel
-        // before sendCommand. Close channel immediately after sendCommand.
-        if (mChannelOpened) {  // Case 1 or 2
-            if (euiccSession) {
-                EuiccSession.get().noteChannelOpen(this);
-            }
-            RequestBuilder builder = getRequestBuilderWithOpenedChannel(requestProvider,
-                    !euiccSession /* closeChannelImmediately */, resultCallback, handler);
-            if (builder == null) {
-                return;
-            }
-            sendCommand(builder.getCommands(), 0 /* index */,
-                    !euiccSession /* closeChannelImmediately */, resultCallback, handler);
-        } else {  // Case 3 or 4
-            if (euiccSession) {
-                EuiccSession.get().noteChannelOpen(this);
-            }
-            openChannel(requestProvider,
-                    !euiccSession /* closeChannelImmediately */, resultCallback, handler);
-        }
-    }
-
-    private RequestBuilder getRequestBuilderWithOpenedChannel(
-            RequestProvider requestProvider,
-            boolean closeChannelImmediately,
-            ApduSenderResultCallback resultCallback,
-            Handler handler) {
-        Throwable requestException = null;
-        int channel =
-                PreferenceManager.getDefaultSharedPreferences(mContext)
-                        .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL);
-        String storedResponse =
-                PreferenceManager.getDefaultSharedPreferences(mContext)
-                        .getString(mChannelResponseKey, "");
-        byte[] selectResponse = Base64.decode(storedResponse, Base64.DEFAULT);
-        RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu);
-        try {
-            requestProvider.buildRequest(selectResponse, builder);
-        } catch (Throwable e) {
-            requestException = e;
-        }
-        if (builder.getCommands().isEmpty() || requestException != null) {
-            logd("Release as commands are empty or exception occurred");
-            returnRespnseOrException(channel, closeChannelImmediately,
-                    null /* response */, requestException, resultCallback, handler);
-            return null;
-        }
-        return builder;
-    }
-
-    private void openChannel(
-            RequestProvider requestProvider,
-            boolean closeChannelImmediately,
-            ApduSenderResultCallback resultCallback,
-            Handler handler) {
-        mOpenChannel.invoke(mAid, new AsyncResultCallback<IccOpenLogicalChannelResponse>() {
-                    @Override
-                    public void onResult(IccOpenLogicalChannelResponse openChannelResponse) {
-                        int channel = openChannelResponse.getChannel();
-                        int status = openChannelResponse.getStatus();
-                        byte[] selectResponse = openChannelResponse.getSelectResponse();
-                        if (status == IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT) {
-                            channel = PreferenceManager.getDefaultSharedPreferences(mContext)
-                                            .getInt(mChannelKey,
-                                                    IccOpenLogicalChannelResponse.INVALID_CHANNEL);
-                            if (channel != IccOpenLogicalChannelResponse.INVALID_CHANNEL) {
-                                logv("Try to use already opened channel: " + channel);
-                                status = IccOpenLogicalChannelResponse.STATUS_NO_ERROR;
-                                String storedResponse = PreferenceManager
-                                        .getDefaultSharedPreferences(mContext)
-                                              .getString(mChannelResponseKey, "");
-                                selectResponse = Base64.decode(storedResponse, Base64.DEFAULT);
-                            }
-                        }
-
-                        if (channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL
-                                || status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR) {
-                            mChannelOpened = false;
-                            resultCallback.onException(
-                                    new ApduException("Failed to open logical channel for AID: "
-                                            + mAid + ", with status: " + status));
-                            return;
-                        }
-                        PreferenceManager.getDefaultSharedPreferences(mContext)
-                                .edit()
-                                .putInt(mChannelKey, channel)
-                                .putString(mChannelResponseKey,
-                                    Base64.encodeToString(selectResponse, Base64.DEFAULT)).apply();
-                        mChannelOpened = true;
-
-                        RequestBuilder builder =
-                                getRequestBuilderWithOpenedChannel(requestProvider,
-                                        closeChannelImmediately, resultCallback, handler);
-                        if (builder == null) {
-                            return;
-                        }
-
-                        sendCommand(builder.getCommands(), 0 /* index */,
-                                closeChannelImmediately, resultCallback, handler);
+        synchronized (mChannelLock) {
+            if (mChannelOpened) {
+                if (!Looper.getMainLooper().equals(Looper.myLooper())) {
+                    logd("Logical channel has already been opened. Wait.");
+                    try {
+                        mChannelLock.wait(WAIT_TIME_MS);
+                    } catch (InterruptedException e) {
+                        // nothing to do
                     }
-                },
-                handler);
+                    if (mChannelOpened) {
+                        AsyncResultHelper.throwException(
+                                new ApduException("The logical channel is still in use."),
+                                resultCallback, handler);
+                        return;
+                    }
+                } else {
+                    AsyncResultHelper.throwException(
+                            new ApduException("The logical channel is in use."),
+                            resultCallback, handler);
+                    return;
+                }
+            }
+            mChannelOpened = true;
+        }
+
+        mOpenChannel.invoke(mAid, new AsyncResultCallback<IccOpenLogicalChannelResponse>() {
+            @Override
+            public void onResult(IccOpenLogicalChannelResponse openChannelResponse) {
+                int channel = openChannelResponse.getChannel();
+                int status = openChannelResponse.getStatus();
+                if (channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL
+                        || status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR) {
+                    synchronized (mChannelLock) {
+                        mChannelOpened = false;
+                        mChannelLock.notify();
+                    }
+                    resultCallback.onException(
+                            new ApduException("Failed to open logical channel opened for AID: "
+                                    + mAid + ", with status: " + status));
+                    return;
+                }
+
+                RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu);
+                Throwable requestException = null;
+                try {
+                    requestProvider.buildRequest(openChannelResponse.getSelectResponse(), builder);
+                } catch (Throwable e) {
+                    requestException = e;
+                }
+                if (builder.getCommands().isEmpty() || requestException != null) {
+                    // Just close the channel if we don't have commands to send or an error
+                    // was encountered.
+                    closeAndReturn(channel, null /* response */, requestException, resultCallback,
+                            handler);
+                    return;
+                }
+                sendCommand(builder.getCommands(), 0 /* index */, resultCallback, handler);
+            }
+        }, handler);
+    }
+
+    /**
+     * Closes any open channel.
+     *
+     * <p>Used by EuiccSession#endSession.
+     */
+    public void closeAnyOpenChannel() {
+        // TODO: implement this. Different from existing closeExistingChannelIfExists()
+        // which is only used in constructor and don't worry about multi-thread racing.
+        // 1. Acquire channel lock
+        // 2. Check sharedpref for existing open channel
+        // 3. Close any open channel
+        // 4. Release channel lock
     }
 
     /**
@@ -271,7 +184,6 @@
     private void sendCommand(
             List<ApduCommand> commands,
             int index,
-            boolean closeChannelImmediately,
             ApduSenderResultCallback resultCallback,
             Handler handler) {
         ApduCommand command = commands.get(index);
@@ -286,21 +198,9 @@
                             public void onResult(IccIoResult fullResponse) {
                                 logv("Full APDU response: " + fullResponse);
                                 int status = (fullResponse.sw1 << 8) | fullResponse.sw2;
-                                if (status != STATUS_NO_ERROR
-                                        && fullResponse.sw1 != SW1_NO_ERROR) {
-                                    if (status == STATUS_CHANNEL_CLOSED) {
-                                        // Channel is closed by EUICC e.g. REFRESH.
-                                        tearDownPreferences();
-                                        mChannelOpened = false;
-                                        // TODO: add retry
-                                    }
-                                    returnRespnseOrException(
-                                            command.channel,
-                                            closeChannelImmediately,
-                                            null /* response */,
-                                            new ApduException(status),
-                                            resultCallback,
-                                            handler);
+                                if (status != STATUS_NO_ERROR && fullResponse.sw1 != SW1_NO_ERROR) {
+                                    closeAndReturn(command.channel, null /* response */,
+                                            new ApduException(status), resultCallback, handler);
                                     return;
                                 }
 
@@ -310,17 +210,11 @@
                                                 fullResponse);
                                 if (continueSendCommand) {
                                     // Sends the next command
-                                    sendCommand(commands, index + 1,
-                                            closeChannelImmediately, resultCallback, handler);
+                                    sendCommand(commands, index + 1, resultCallback, handler);
                                 } else {
                                     // Returns the result of the last command
-                                    returnRespnseOrException(
-                                            command.channel,
-                                            closeChannelImmediately,
-                                            fullResponse.payload,
-                                            null /* exception */,
-                                            resultCallback,
-                                            handler);
+                                    closeAndReturn(command.channel, fullResponse.payload,
+                                            null /* exception */, resultCallback, handler);
                                 }
                             }
                         }, handler);
@@ -343,7 +237,7 @@
             AsyncResultCallback<IccIoResult> resultCallback,
             Handler handler) {
         ByteArrayOutputStream resultBuilder =
-            responseBuilder == null ? new ByteArrayOutputStream() : responseBuilder;
+                responseBuilder == null ? new ByteArrayOutputStream() : responseBuilder;
         if (lastResponse.payload != null) {
             try {
                 resultBuilder.write(lastResponse.payload);
@@ -369,41 +263,6 @@
                 }, handler);
     }
 
-    private void tearDownPreferences() {
-        PreferenceManager.getDefaultSharedPreferences(mContext)
-                .edit()
-                .remove(mChannelKey)
-                .remove(mChannelResponseKey)
-                .apply();
-    }
-
-    /**
-     * Fires the {@code resultCallback} to return a response or exception. Also
-     * closes the open logical channel if {@code closeChannelImmediately} is {@code true}.
-     */
-    private void returnRespnseOrException(
-            int channel,
-            boolean closeChannelImmediately,
-            @Nullable byte[] response,
-            @Nullable Throwable exception,
-            ApduSenderResultCallback resultCallback,
-            Handler handler) {
-        if (closeChannelImmediately) {
-            closeAndReturn(
-                    channel,
-                    response,
-                    exception,
-                    resultCallback,
-                    handler);
-        } else {
-            releaseChannelLockAndReturn(
-                    response,
-                    exception,
-                    resultCallback,
-                    handler);
-        }
-    }
-
     /**
      * Closes the opened logical channel.
      *
@@ -421,9 +280,10 @@
         mCloseChannel.invoke(channel, new AsyncResultCallback<Boolean>() {
             @Override
             public void onResult(Boolean aBoolean) {
-                tearDownPreferences();
-                mChannelOpened = false;
-                releaseChannelLock();
+                synchronized (mChannelLock) {
+                    mChannelOpened = false;
+                    mChannelLock.notify();
+                }
 
                 if (exception == null) {
                     resultCallback.onResult(response);
@@ -433,99 +293,4 @@
             }
         }, handler);
     }
-
-    /**
-     * Cleanup the existing opened channel which remained opened earlier due
-     * to:
-     *
-     * <p> 1) onging EuiccSession. This will be called by {@link EuiccSession#endSession()}
-     * from non-main-thread. Or,
-     *
-     * <p> 2) telephony crash. This will be called by constructor from main-thread.
-     */
-    public void closeAnyOpenChannel() {
-        if (!acquireChannelLock()) {
-            // This cannot happen for case 2) when called by constructor
-            loge("[closeAnyOpenChannel] failed to acquire channel lock");
-            return;
-        }
-        int channelId = PreferenceManager.getDefaultSharedPreferences(mContext)
-                .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL);
-        if (channelId == IccOpenLogicalChannelResponse.INVALID_CHANNEL) {
-            releaseChannelLock();
-            return;
-        }
-        logv("[closeAnyOpenChannel] closing the open channel : " +  channelId);
-        mCloseChannel.invoke(channelId, new AsyncResultCallback<Boolean>() {
-            @Override
-            public void onResult(Boolean isSuccess) {
-                if (isSuccess) {
-                    logv("[closeAnyOpenChannel] Channel closed successfully: " + channelId);
-                    tearDownPreferences();
-                }
-                // Even if CloseChannel failed, pretend that the channel is closed.
-                // So next send() will try open the channel again. If the channel is
-                // indeed still open, we use the channelId saved in sharedPref.
-                mChannelOpened = false;
-                releaseChannelLock();
-            }
-        }, mHandler);
-    }
-
-    // releases channel and callback
-    private void releaseChannelLockAndReturn(
-            @Nullable byte[] response,
-            @Nullable Throwable exception,
-            ApduSenderResultCallback resultCallback,
-            Handler handler) {
-        handler.post(
-                () -> {
-                    releaseChannelLock();
-                    if (exception == null) {
-                        resultCallback.onResult(response);
-                    } else {
-                        resultCallback.onException(exception);
-                    }
-                });
-    }
-
-    private void releaseChannelLock() {
-        synchronized (mChannelInUseLock) {
-            logd("Channel lock released.");
-            mChannelInUse = false;
-            mChannelInUseLock.notify();
-        }
-    }
-
-    /**
-     * Acquires channel lock and returns {@code true} if successful.
-     *
-     * <p>It fails and returns {@code false} when:
-     * <ul>
-     *   <li>Called from main thread, and mChannelInUse=true, fails immediately.
-     *   <li>Called from non main thread, and mChannelInUse=true after 2 seconds waiting, fails.
-     * </ul>
-     */
-    private boolean acquireChannelLock() {
-        synchronized (mChannelInUseLock) {
-            if (mChannelInUse) {
-                if (!Looper.getMainLooper().equals(Looper.myLooper())) {
-                    logd("Logical channel is in use. Wait.");
-                    try {
-                        mChannelInUseLock.wait(WAIT_TIME_MS);
-                    } catch (InterruptedException e) {
-                        // nothing to do
-                    }
-                    if (mChannelInUse) {
-                        return false;
-                    }
-                } else {
-                    return false;
-                }
-            }
-            mChannelInUse = true;
-            logd("Channel lock acquired.");
-            return true;
-        }
-    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
index a645439..fae5e8b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
@@ -981,6 +981,8 @@
 
         mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.TIRAMISU;
         doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(anyString(), anyInt());
+        doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfoAsUser(
+                anyString(), anyInt(), any(UserHandle.class));
         mContextFixture.addCallingOrSelfPermission("");
         mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
         mContextFixture.addCallingOrSelfPermission(
@@ -1077,6 +1079,8 @@
 
         mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.TIRAMISU;
         doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(anyString(), anyInt());
+        doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfoAsUser(
+                anyString(), anyInt(), any(UserHandle.class));
         mContextFixture.addCallingOrSelfPermission("");
         mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
         mContextFixture.addCallingOrSelfPermission(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index dd4d63a..d80c9a2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -582,6 +582,7 @@
         doReturn(true).when(mFeatureFlags).minimalTelephonyCdmCheck();
         doReturn(true).when(mFeatureFlags).supportNetworkProvider();
         doReturn(true).when(mFeatureFlags).hsumBroadcast();
+        doReturn(true).when(mFeatureFlags).hsumPackageManager();
 
         TelephonyManager.disableServiceHandleCaching();
         PropertyInvalidatedCache.disableForTestMode();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 7f31f30..db46a00 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -3593,12 +3593,14 @@
         processAllMessages();
         verify(mMockNotificationManager, times(1)).notifyAsUser(anyString(), anyInt(), any(),
                 any());
-        assertTrue(mSharedPreferences.getBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false));
+        // Just by showing notification we do not update the pref file , only once user interact
+        // only we will update the pref value to true.
+        assertFalse(mSharedPreferences.getBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false));
 
         // Check don't display again after displayed already a system notification.
         sendServiceStateChangedEvent();
         processAllMessages();
-        verify(mMockNotificationManager, times(1)).notifyAsUser(anyString(), anyInt(), any(),
+        verify(mMockNotificationManager, times(2)).notifyAsUser(anyString(), anyInt(), any(),
                 any());
     }
 
@@ -4116,7 +4118,7 @@
         assertTrue(mSatelliteControllerUT.isCarrierRoamingNtnEligible(mPhone));
         verify(mPhone, times(0)).notifyCarrierRoamingNtnEligibleStateChanged(eq(true));
         verify(mPhone2, times(0)).notifyCarrierRoamingNtnEligibleStateChanged(anyBoolean());
-        verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(),
+        verify(mMockNotificationManager, times(2)).cancelAsUser(anyString(), anyInt(),
                 any());
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
index 358ec47..541cee2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
@@ -29,6 +29,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -67,6 +70,7 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.flags.Flags;
+import com.android.internal.telephony.metrics.SatelliteStats;
 
 import org.junit.After;
 import org.junit.Before;
@@ -118,6 +122,8 @@
     private Uri mTestConnectionAddress = Uri.parse("tel:1234");
     private TestSOSMessageRecommender mTestSOSMessageRecommender;
     private ServiceState mServiceState2;
+    @Mock
+    private SatelliteStats mMockSatelliteStats;
 
     @Before
     public void setUp() throws Exception {
@@ -153,6 +159,10 @@
         when(mServiceState2.getState()).thenReturn(STATE_OUT_OF_SERVICE);
         when(mPhone.isImsRegistered()).thenReturn(false);
         when(mPhone2.isImsRegistered()).thenReturn(false);
+        replaceInstance(SatelliteStats.class, "sInstance", null,
+                mMockSatelliteStats);
+        doNothing().when(mMockSatelliteStats).onSatelliteSosMessageRecommender(
+                any(SatelliteStats.SatelliteSosMessageRecommenderParams.class));
     }
 
     @After
@@ -165,6 +175,8 @@
         testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
                 DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS,
                 DEFAULT_T911_HANDOVER_INTENT_ACTION);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
@@ -177,6 +189,8 @@
         testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
                 "android.com.vendor.message", "android.com.vendor.message.SmsApp",
                 DEFAULT_HANDOVER_INTENT_ACTION);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
@@ -188,6 +202,8 @@
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
                 DEFAULT_HANDOVER_INTENT_ACTION);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
@@ -197,6 +213,8 @@
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
                 DEFAULT_HANDOVER_INTENT_ACTION);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
@@ -204,16 +222,17 @@
         when(mServiceState.getState()).thenReturn(STATE_OUT_OF_SERVICE);
         when(mServiceState2.getState()).thenReturn(STATE_OUT_OF_SERVICE);
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(null);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(null, false);
         processAllMessages();
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
     }
 
     private void testTimeoutBeforeEmergencyCallEnd(int expectedHandoverType,
             String expectedPackageName, String expectedClassName, String expectedAction) {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertRegisterForStateChangedEventsTriggered(mPhone, 1,  1);
@@ -239,6 +258,8 @@
         }
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
@@ -246,7 +267,7 @@
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         mTestSatelliteController.setIsSatelliteViaOemProvisioned(false);
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
@@ -266,6 +287,8 @@
         assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertFalse(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
@@ -273,7 +296,7 @@
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         mTestSatelliteController.isOemEnabledSatelliteSupported = false;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
@@ -302,17 +325,21 @@
     @Test
     public void testStopTrackingCallBeforeTimeout_ConnectionActive() {
         testStopTrackingCallBeforeTimeout(Connection.STATE_ACTIVE);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertFalse(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testStopTrackingCallBeforeTimeout_ConnectionDisconnected() {
         testStopTrackingCallBeforeTimeout(Connection.STATE_DISCONNECTED);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertFalse(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testNetworkStateChangedBeforeTimeout() {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -337,11 +364,13 @@
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testSatelliteProvisionStateChangedBeforeTimeout() {
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
 
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -357,8 +386,11 @@
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertFalse(mTestSOSMessageRecommender.isDialerNotified());
+        reset(mMockSatelliteStats);
 
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -387,12 +419,14 @@
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 2);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 2, 2);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testEmergencyCallRedialBeforeTimeout() {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -400,7 +434,7 @@
         assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
 
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -426,35 +460,45 @@
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testCellularServiceStateChangedBeforeTimeout_InServiceToOutOfService() {
         testCellularServiceStateChangedBeforeTimeout(
                 ServiceState.STATE_IN_SERVICE, STATE_OUT_OF_SERVICE);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testCellularServiceStateChangedBeforeTimeout_InServiceToPowerOff() {
         testCellularServiceStateChangedBeforeTimeout(
                 ServiceState.STATE_IN_SERVICE, ServiceState.STATE_POWER_OFF);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testCellularServiceStateChangedBeforeTimeout_EmergencyOnlyToOutOfService() {
         testCellularServiceStateChangedBeforeTimeout(
                 ServiceState.STATE_EMERGENCY_ONLY, STATE_OUT_OF_SERVICE);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testCellularServiceStateChangedBeforeTimeout_EmergencyOnlyToPowerOff() {
         testCellularServiceStateChangedBeforeTimeout(
                 ServiceState.STATE_EMERGENCY_ONLY, ServiceState.STATE_POWER_OFF);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() {
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
 
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -471,12 +515,15 @@
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertFalse(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
     public void testSatelliteNotAllowedInCurrentLocation() {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -498,6 +545,8 @@
         assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
+        verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
+        assertFalse(mTestSOSMessageRecommender.isDialerNotified());
     }
 
     @Test
@@ -508,11 +557,12 @@
                 mContext,
                 Looper.myLooper(),
                 satelliteController, mTestImsManager);
-        testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
 
         assertFalse(testSOSMessageRecommender.isTimerStarted());
         assertEquals(0, testSOSMessageRecommender.getCountOfTimerStarted());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
     }
 
     @Test
@@ -538,16 +588,17 @@
         // Both OEM and carrier don't support satellite
         mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = false;
         mTestSatelliteController.isOemEnabledSatelliteSupported = false;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(0, mTestSOSMessageRecommender.getTimeOutMillis());
 
         // Only OEM support satellite
         mTestSatelliteController.isOemEnabledSatelliteSupported = true;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
                 mTestSOSMessageRecommender.getTimeOutMillis());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
 
         // Both OEM and carrier support satellite, but device is not connected to carrier satellite
         // within hysteresis time. Thus, OEM timer will be used.
@@ -556,10 +607,11 @@
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
                 carrierTimeoutMillis;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
                 mTestSOSMessageRecommender.getTimeOutMillis());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
 
         // Both OEM and carrier support satellite, and device is connected to carrier satellite
         // within hysteresis time. Thus, carrier timer will be used.
@@ -567,9 +619,10 @@
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
         mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
                 carrierTimeoutMillis;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(carrierTimeoutMillis, mTestSOSMessageRecommender.getTimeOutMillis());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
     }
 
     @Test
@@ -578,9 +631,10 @@
 
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
         mTestSatelliteController.mIsSatelliteViaOemProvisioned = true;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
                 mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
 
         mSetFlagsRule.disableFlags(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN);
     }
@@ -591,9 +645,10 @@
 
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
         mTestSatelliteController.mIsSatelliteViaOemProvisioned = false;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
                 mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
 
         mSetFlagsRule.disableFlags(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN);
     }
@@ -604,22 +659,23 @@
 
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         mTestSatelliteController.mIsSatelliteViaOemProvisioned = true;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
                 mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
 
         mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         mTestSatelliteController.mIsSatelliteViaOemProvisioned = false;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
                 mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
 
         mSetFlagsRule.disableFlags(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN);
     }
 
     private void testStopTrackingCallBeforeTimeout(
             @Connection.ConnectionState int connectionState) {
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
 
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -641,7 +697,7 @@
             @ServiceState.RegState int availableServiceState,
             @ServiceState.RegState int unavailableServiceState) {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -896,6 +952,7 @@
                 isSatelliteAllowedCallback = null;
         private ComponentName mSmsAppComponent = new ComponentName(
                 DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS);
+        private boolean mIsDialerNotified;
 
         /**
          * Create an instance of SatelliteSOSMessageRecommender.
@@ -924,6 +981,12 @@
             isSatelliteAllowedCallback = callback;
         }
 
+        @Override
+        protected void reportESosRecommenderDecision(boolean isDialerNotified) {
+            super.reportESosRecommenderDecision(isDialerNotified);
+            mIsDialerNotified = isDialerNotified;
+        }
+
         public boolean isTimerStarted() {
             return hasMessages(EVENT_TIME_OUT);
         }
@@ -939,6 +1002,10 @@
         public long getTimeOutMillis() {
             return mTimeoutMillis;
         }
+
+        public boolean isDialerNotified() {
+            return mIsDialerNotified;
+        }
     }
 
     private static class TestConnection extends Connection {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
index 172211c..a65814e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
@@ -16,52 +16,36 @@
 
 package com.android.internal.telephony.uicc.euicc.apdu;
 
-import static com.android.internal.telephony.CommandException.Error.RADIO_NOT_AVAILABLE;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.os.Handler;
 import android.os.Looper;
-import android.platform.test.flag.junit.SetFlagsRule;
-import android.preference.PreferenceManager;
-import android.telephony.IccOpenLogicalChannelResponse;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.euicc.EuiccSession;
-import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.IccUtils;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mockito;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class ApduSenderTest {
-    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     private static class ResponseCaptor extends ApduSenderResultCallback {
         public byte[] response;
@@ -91,13 +75,6 @@
         }
     }
 
-    private static final int PHONE_ID = 0;
-    private static final String SESSION_ID = "TEST";
-    // keep in sync with ApduSender.mChannelKey
-    private static final String SHARED_PREFS_KEY_CHANNEL_ID = "esim-channel_0";
-    // keep in sync with ApduSender.mChannelResponseKey
-    private static final String SHARED_PREFS_KEY_CHANNEL_RESPONSE = "esim-res-id_0";
-
     // Mocked classes
     private CommandsInterface mMockCi;
 
@@ -105,20 +82,19 @@
     private Handler mHandler;
     private ResponseCaptor mResponseCaptor;
     private byte[] mSelectResponse;
+    private static final String AID = "B2C3D4";
     private ApduSender mSender;
 
     @Before
     public void setUp() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_OPTIMIZATION_APDU_SENDER);
-
         mMockCi = mock(CommandsInterface.class);
-        mLooper = TestableLooper.get(this);
-        mHandler = new Handler(mLooper.getLooper());
+        mHandler = new Handler(Looper.myLooper());
+
         mResponseCaptor = new ResponseCaptor();
         mSelectResponse = null;
 
-        mSender = new ApduSender(InstrumentationRegistry.getContext(), PHONE_ID,
-                            mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */);
+        mSender = new ApduSender(mMockCi, AID, false /* supportExtendedApdu */);
+        mLooper = TestableLooper.get(this);
     }
 
     @After
@@ -129,19 +105,6 @@
         mResponseCaptor = null;
         mSelectResponse = null;
         mSender = null;
-
-        EuiccSession.get().endSession(SESSION_ID);
-        clearSharedPreferences();
-    }
-
-    @Test
-    public void testWrongAid_throwsIllegalArgumentException() {
-        String wrongAid = "-1";
-
-        assertThrows(IllegalArgumentException.class, () -> {
-            new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */,
-                            mMockCi, wrongAid, false /* supportExtendedApdu */);
-        });
     }
 
     @Test
@@ -156,7 +119,7 @@
         assertEquals("A1A1A19000", IccUtils.bytesToHexString(mSelectResponse));
         assertNull(mResponseCaptor.response);
         assertNull(mResponseCaptor.exception);
-        verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
+        verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any());
         verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
     }
 
@@ -172,7 +135,7 @@
         assertNull("Request provider should not be called when failed to open channel.",
                 mSelectResponse);
         assertTrue(mResponseCaptor.exception instanceof ApduException);
-        verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
+        verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any());
     }
 
     @Test
@@ -186,11 +149,8 @@
         mLooper.processAllMessages();
 
         assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
-        InOrder inOrder = inOrder(mMockCi);
-        inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
-        inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
-                eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
-        inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
+        verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+                eq(3), eq(0), eq("a"), anyBoolean(), any());
     }
 
     @Test
@@ -209,17 +169,14 @@
         mLooper.processAllMessages();
 
         assertEquals("A4", IccUtils.bytesToHexString(mResponseCaptor.response));
-        InOrder inOrder = inOrder(mMockCi);
-        inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
-        inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
-                eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
-        inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
-                eq(1), eq(2), eq(3), eq(1), eq("ab"), anyBoolean(), any());
-        inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
-                eq(1), eq(2),  eq(3), eq(0), eq(""), anyBoolean(), any());
-        inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81),
-                eq(0xE2), eq(0x91), eq(0), eq(2), eq("abcd"), anyBoolean(), any());
-        inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
+        verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+                eq(3), eq(0), eq("a"), anyBoolean(), any());
+        verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+                eq(3), eq(1), eq("ab"), anyBoolean(), any());
+        verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+                eq(3), eq(0), eq(""), anyBoolean(), any());
+        verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91),
+                eq(0), eq(2), eq("abcd"), anyBoolean(), any());
     }
 
     @Test
@@ -382,157 +339,6 @@
 
         assertNull("Should not open channel when another one is already opened.", mSelectResponse);
         assertTrue(mResponseCaptor.exception instanceof ApduException);
-        verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
-    }
-
-    @Test
-    public void testConstructor_closeOpenChannelInSharedPreference() throws InterruptedException {
-        // Open a channel and not close it, by making CI.iccTransmitApduLogicalChannel throw.
-        int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
-        doThrow(new RuntimeException()).when(mMockCi).iccTransmitApduLogicalChannel(
-                eq(channel), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), any(),
-                anyBoolean(), any());
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-        // Stub close channel
-        reset(mMockCi);
-        LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
-
-        // Call constructor
-        mSender = new ApduSender(InstrumentationRegistry.getContext(), PHONE_ID,
-                            mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */);
-        mLooper.processAllMessages();
-
-        // The constructor should have closed channel
-        verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
-        assertEquals(-1, getChannelIdFromSharedPreferences());
-    }
-
-    @Test
-    public void testSend_OpenChannelFailedNoSuchElement_useChannelInSharedPreference() {
-        // Open a channel but not close, by making CI.iccTransmitApduLogicalChannel throw.
-        int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
-        doThrow(new RuntimeException()).when(mMockCi).iccTransmitApduLogicalChannel(
-                eq(channel), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), any(),
-                anyBoolean(), any());
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-        reset(mMockCi);
-        // Constructor fails to close channel
-        LogicalChannelMocker.mockCloseLogicalChannel(
-                mMockCi, channel, new CommandException(RADIO_NOT_AVAILABLE));
-        mSender = new ApduSender(InstrumentationRegistry.getContext(), PHONE_ID,
-                            mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */);
-        mLooper.processAllMessages();
-        reset(mMockCi);
-        // Stub open channel failure NO_SUCH_ELEMENT
-        LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi,
-                new CommandException(CommandException.Error.NO_SUCH_ELEMENT));
-        LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, "A1A1A19000");
-        LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
-
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-
-        // open channel would fail, and send/close would succeed because of
-        // previous open response saved in sharedPref
-        InOrder inOrder = inOrder(mMockCi);
-        inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
-        inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel),
-                 eq(channel | 10), eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
-        inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
-        inOrder.verifyNoMoreInteractions();
-    }
-
-    @Test
-    public void testSend_euiccSession_shouldNotCloseChannel()
-            throws InterruptedException {
-        int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
-        LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, "A1A1A19000");
-        LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
-        EuiccSession.get().startSession(SESSION_ID);
-
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-
-        assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
-        InOrder inOrder = inOrder(mMockCi);
-        inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
-        inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
-                eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
-        // No iccCloseLogicalChannel
-        inOrder.verifyNoMoreInteractions();
-    }
-
-    @Test
-    public void testSendTwice_euiccSession_shouldOpenChannelOnceNotCloseChannel()
-            throws InterruptedException {
-        int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
-        LogicalChannelMocker.mockSendToLogicalChannel(
-                    mMockCi, channel, "A1A1A19000", "A1A1A19000");
-        LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
-        EuiccSession.get().startSession(SESSION_ID);
-
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-
-        assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
-        InOrder inOrder = inOrder(mMockCi);
-        // iccOpenLogicalChannel once
-        inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
-        // iccTransmitApduLogicalChannel twice
-        inOrder.verify(mMockCi, times(2)).iccTransmitApduLogicalChannel(eq(channel),
-                 eq(channel | 10), eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
-        // No iccCloseLogicalChannel
-        inOrder.verifyNoMoreInteractions();
-    }
-
-    @Test
-    public void testSendTwice_thenEndSession() throws InterruptedException {
-        int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
-        LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel,
-                "A1A1A19000", "A1A1A19000");
-        LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
-        EuiccSession.get().startSession(SESSION_ID);
-
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-        mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
-                10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
-        mLooper.processAllMessages();
-        EuiccSession.get().endSession(SESSION_ID);
-        mLooper.processAllMessages();
-
-        assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
-        InOrder inOrder = inOrder(mMockCi);
-        // iccOpenLogicalChannel once
-        inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
-        // iccTransmitApduLogicalChannel twice
-        inOrder.verify(mMockCi, times(2)).iccTransmitApduLogicalChannel(eq(channel),
-                 eq(channel | 10), eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
-        // iccCloseLogicalChannel once
-        inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
-    }
-
-    private int getChannelIdFromSharedPreferences() {
-        return PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getContext())
-                .getInt(SHARED_PREFS_KEY_CHANNEL_ID, -1);
-    }
-
-    private void clearSharedPreferences() {
-        PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getContext())
-                .edit()
-                .remove(SHARED_PREFS_KEY_CHANNEL_ID)
-                .remove(SHARED_PREFS_KEY_CHANNEL_RESPONSE)
-                .apply();
+        verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(AID), anyInt(), any());
     }
 }