Merge "Fix NPE in TestSatelliteService" into main
diff --git a/ecc/input/eccdata.txt b/ecc/input/eccdata.txt
index 83b5c39..fe11383 100644
--- a/ecc/input/eccdata.txt
+++ b/ecc/input/eccdata.txt
@@ -906,6 +906,16 @@
       types: TYPE_UNSPECIFIED
       routing: NORMAL
   }
+  eccs {
+      phone_number: "028"
+      types: TYPE_UNSPECIFIED
+      routing: NORMAL
+  }
+  eccs {
+      phone_number: "116000"
+      types: TYPE_UNSPECIFIED
+      routing: NORMAL
+  }
   ecc_fallback: "112"
 }
 countries {
diff --git a/ecc/output/eccdata b/ecc/output/eccdata
index 3f28a3a..55d8151 100644
--- a/ecc/output/eccdata
+++ b/ecc/output/eccdata
Binary files differ
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index c27fee6..8dd6abd 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -850,7 +850,7 @@
     <string name="radio_info_ims_reg_status_not_registered" msgid="8045821447288876085">"ਰਜਿਸਟਰ ਨਹੀਂ ਕੀਤੀ ਗਈ"</string>
     <string name="radio_info_ims_feature_status_available" msgid="6493200914756969292">"ਉਪਲਬਧ"</string>
     <string name="radio_info_ims_feature_status_unavailable" msgid="8930391136839759778">"ਅਣਉਪਲਬਧ"</string>
-    <string name="radio_info_ims_reg_status" msgid="25582845222446390">"IMS ਰਜਿਸਟਰੇਸ਼ਨ: <xliff:g id="STATUS">%1$s</xliff:g>\nLTE \'ਤੇ ਅਵਾਜ਼: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nਵਾਈ-ਫਾਈ \'ਤੇ ਅਵਾਜ਼ੀ ਕਾਲ: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nਵੀਡੀਓ ਕਾਲਿੰਗ: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nUT ਇੰਟਰਫੇਸ: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
+    <string name="radio_info_ims_reg_status" msgid="25582845222446390">"IMS ਰਜਿਸਟਰੇਸ਼ਨ: <xliff:g id="STATUS">%1$s</xliff:g>\nLTE \'ਤੇ ਅਵਾਜ਼: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nਵਾਈ-ਫਾਈ \'ਤੇ ਅਵਾਜ਼ੀ ਕਾਲ: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nਵੀਡੀਓ ਕਾਲਿੰਗ: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nUT ਇੰਟਰਫ਼ੇਸ: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
     <string name="radioInfo_service_in" msgid="45753418231446400">"ਸੇਵਾ ਵਿੱਚ"</string>
     <string name="radioInfo_service_out" msgid="287972405416142312">"ਸੇਵਾ ਵਿੱਚ ਨਹੀਂ"</string>
     <string name="radioInfo_service_emergency" msgid="4763879891415016848">"ਸਿਰਫ਼ ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ"</string>
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index b11431c..4773a83 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -554,7 +554,7 @@
 
             mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
 
-            phoneMgr = PhoneInterfaceManager.init(this);
+            phoneMgr = PhoneInterfaceManager.init(this, featureFlags);
 
             imsRcsController = ImsRcsController.init(this);
 
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 26d1e73..4e673d8 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -209,6 +209,7 @@
 import com.android.internal.telephony.domainselection.DomainSelectionResolver;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.euicc.EuiccConnector;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
@@ -402,6 +403,7 @@
     private static List<String> sThermalMitigationAllowlistedPackages = new ArrayList<>();
 
     private final PhoneGlobals mApp;
+    private final FeatureFlags mFeatureFlags;
     private final CallManager mCM;
     private final ImsResolver mImsResolver;
 
@@ -2212,8 +2214,8 @@
                     onCompleted = obtainMessage(EVENT_PURCHASE_PREMIUM_CAPABILITY_DONE, request);
                     PurchasePremiumCapabilityArgument arg =
                             (PurchasePremiumCapabilityArgument) request.argument;
-                    SlicePurchaseController.getInstance(request.phone).purchasePremiumCapability(
-                            arg.capability, onCompleted);
+                    SlicePurchaseController.getInstance(request.phone, mFeatureFlags)
+                            .purchasePremiumCapability(arg.capability, onCompleted);
                     break;
                 }
 
@@ -2426,10 +2428,10 @@
      * Initialize the singleton PhoneInterfaceManager instance.
      * This is only done once, at startup, from PhoneApp.onCreate().
      */
-    /* package */ static PhoneInterfaceManager init(PhoneGlobals app) {
+    /* package */ static PhoneInterfaceManager init(PhoneGlobals app, FeatureFlags featureFlags) {
         synchronized (PhoneInterfaceManager.class) {
             if (sInstance == null) {
-                sInstance = new PhoneInterfaceManager(app);
+                sInstance = new PhoneInterfaceManager(app, featureFlags);
             } else {
                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
             }
@@ -2438,8 +2440,9 @@
     }
 
     /** Private constructor; @see init() */
-    private PhoneInterfaceManager(PhoneGlobals app) {
+    private PhoneInterfaceManager(PhoneGlobals app, FeatureFlags featureFlags) {
         mApp = app;
+        mFeatureFlags = featureFlags;
         mCM = PhoneGlobals.getInstance().mCM;
         mImsResolver = ImsResolver.getInstance();
         mSatelliteController = SatelliteController.getInstance();
@@ -11542,7 +11545,7 @@
         }
         final long identity = Binder.clearCallingIdentity();
         try {
-            return SlicePurchaseController.getInstance(phone)
+            return SlicePurchaseController.getInstance(phone, mFeatureFlags)
                     .isPremiumCapabilityAvailableForPurchase(capability);
         } finally {
             Binder.restoreCallingIdentity(identity);
diff --git a/src/com/android/phone/slice/SlicePurchaseController.java b/src/com/android/phone/slice/SlicePurchaseController.java
index 26d70d2..9a42e16 100644
--- a/src/com/android/phone/slice/SlicePurchaseController.java
+++ b/src/com/android/phone/slice/SlicePurchaseController.java
@@ -58,6 +58,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -309,6 +310,8 @@
 
     /** The Phone instance used to create the SlicePurchaseController. */
     @NonNull private final Phone mPhone;
+    /** Feature flags to control behavior and errors. */
+    @NonNull private final FeatureFlags mFeatureFlags;
     /** The set of capabilities that are pending network setup. */
     @NonNull private final Set<Integer> mPendingSetupCapabilities = new HashSet<>();
     /** The set of throttled capabilities. */
@@ -417,10 +420,11 @@
                     logd("Slice purchase application unable to show notification for capability: "
                             + TelephonyManager.convertPremiumCapabilityToString(capability)
                             + " because the user has disabled notifications.");
+                    int error = mFeatureFlags.slicingAdditionalErrorCodes()
+                            ? TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED
+                            : TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED;
                     SlicePurchaseController.getInstance(phoneId)
-                            .handlePurchaseResult(capability,
-                            TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED,
-                            true);
+                            .handlePurchaseResult(capability, error, true);
                     break;
                 }
                 case ACTION_SLICE_PURCHASE_APP_RESPONSE_SUCCESS: {
@@ -449,14 +453,16 @@
      * @param phone The Phone to get the SlicePurchaseController for.
      * @return The static SlicePurchaseController instance.
      */
-    @NonNull public static synchronized SlicePurchaseController getInstance(@NonNull Phone phone) {
+    @NonNull public static synchronized SlicePurchaseController getInstance(@NonNull Phone phone,
+            @NonNull FeatureFlags featureFlags) {
         // TODO: Add listeners for multi sim setting changed (maybe carrier config changed too)
         //  that dismiss notifications and update SlicePurchaseController instance
         int phoneId = phone.getPhoneId();
         if (sInstances.get(phoneId) == null) {
             HandlerThread handlerThread = new HandlerThread("SlicePurchaseController");
             handlerThread.start();
-            sInstances.put(phoneId, new SlicePurchaseController(phone, handlerThread.getLooper()));
+            sInstances.put(phoneId,
+                    new SlicePurchaseController(phone, featureFlags, handlerThread.getLooper()));
         }
         return sInstances.get(phoneId);
     }
@@ -476,12 +482,15 @@
      * Create a SlicePurchaseController for the given phone on the given looper.
      *
      * @param phone The Phone to create the SlicePurchaseController for.
+     * @param featureFlags The FeatureFlags that are supported.
      * @param looper The Looper to run the SlicePurchaseController on.
      */
     @VisibleForTesting
-    public SlicePurchaseController(@NonNull Phone phone, @NonNull Looper looper) {
+    public SlicePurchaseController(@NonNull Phone phone, @NonNull FeatureFlags featureFlags,
+            @NonNull Looper looper) {
         super(looper);
         mPhone = phone;
+        mFeatureFlags = featureFlags;
         // TODO: Create a cached value for slicing config in DataIndication and initialize here
         mPhone.mCi.registerForSlicingConfigChanged(this, EVENT_SLICING_CONFIG_CHANGED, null);
         mIsSlicingUpsellEnabled = DeviceConfig.getBoolean(
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index b7bba84..b925c43 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -590,6 +590,24 @@
                         releaseEmergencyCallDomainSelection(false);
                     }
                 }
+
+                @Override
+                public void onConnectionPropertiesChanged(Connection connection,
+                        int connectionProperties) {
+                    if ((connection == null) || (mEmergencyStateTracker == null)) {
+                        return;
+                    }
+                    TelephonyConnection c = (TelephonyConnection) connection;
+                    com.android.internal.telephony.Connection origConn = c.getOriginalConnection();
+                    if ((origConn == null) || (!origConn.getState().isAlive())) {
+                        // ignore if there is no original connection alive
+                        Log.i(this, "onConnectionPropertiesChanged without orig connection alive");
+                        return;
+                    }
+                    Log.i(this, "onConnectionPropertiesChanged prop=" + connectionProperties);
+                    mEmergencyStateTracker.onEmergencyCallPropertiesChanged(connectionProperties,
+                            c.getTelecomCallId());
+                }
             };
 
     private final TelephonyConnection.TelephonyConnectionListener
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
index 047c8d4..929a2e5 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
@@ -21,6 +21,8 @@
 import android.content.Intent;
 import android.os.Binder;
 import android.os.IBinder;
+import android.telephony.IBooleanConsumer;
+import android.telephony.IIntegerConsumer;
 import android.telephony.satellite.AntennaDirection;
 import android.telephony.satellite.AntennaPosition;
 import android.telephony.satellite.SatelliteManager;
@@ -36,8 +38,6 @@
 import android.telephony.satellite.stub.SatelliteService;
 import android.util.Log;
 
-import com.android.internal.telephony.IBooleanConsumer;
-import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.util.FunctionalUtils;
 import com.android.telephony.Rlog;
 
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index e702279..bea4271 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -44,6 +44,7 @@
 import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 
 import org.junit.Before;
@@ -66,6 +67,8 @@
     PhoneGlobals mPhoneGlobals;
     @Mock
     Phone mPhone;
+    @Mock
+    FeatureFlags mFeatureFlags;
 
     @Mock
     private SubscriptionManagerService mSubscriptionManagerService;
@@ -78,7 +81,7 @@
         // global singleton, but the context that is passed in is unused if the phone app is already
         // alive on a test devices. You must use the spy to mock behavior. Mocks stemming from the
         // passed context will remain unused.
-        mPhoneInterfaceManager = spy(PhoneInterfaceManager.init(mPhoneGlobals));
+        mPhoneInterfaceManager = spy(PhoneInterfaceManager.init(mPhoneGlobals, mFeatureFlags));
         doReturn(mSubscriptionManagerService).when(mPhoneInterfaceManager)
                 .getSubscriptionManagerService();
         TelephonyManager.setupISubForTest(mSubscriptionManagerService);
diff --git a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
index ca67d63..5637c3a 100644
--- a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
+++ b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
@@ -62,6 +62,7 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.data.DataSettingsManager;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -92,6 +93,7 @@
     private static final long THROTTLE_TIMEOUT = 4000;
 
     @Mock Phone mPhone;
+    @Mock FeatureFlags mFeatureFlags;
     @Mock CarrierConfigManager mCarrierConfigManager;
     @Mock CommandsInterface mCommandsInterface;
     @Mock ServiceState mServiceState;
@@ -153,7 +155,7 @@
 
         // create a spy to mock final PendingIntent methods
         SlicePurchaseController slicePurchaseController =
-                new SlicePurchaseController(mPhone, mHandler.getLooper());
+                new SlicePurchaseController(mPhone, mFeatureFlags, mHandler.getLooper());
         mSlicePurchaseController = spy(slicePurchaseController);
         doReturn(null).when(mSlicePurchaseController).createPendingIntent(
                 anyString(), anyInt(), anyBoolean());
@@ -644,6 +646,7 @@
 
     @Test
     public void testPurchasePremiumCapabilityResultNotificationsDisabled() {
+        doReturn(true).when(mFeatureFlags).slicingAdditionalErrorCodes();
         sendValidPurchaseRequest();
 
         // broadcast NOTIFICATIONS_DISABLED response from slice purchase application
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index f0d19f1..d467def 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -16,6 +16,7 @@
 
 package com.android.services.telephony;
 
+import static android.telecom.Connection.PROPERTY_WIFI;
 import static android.telephony.DisconnectCause.EMERGENCY_PERM_FAILURE;
 import static android.telephony.DisconnectCause.EMERGENCY_TEMP_FAILURE;
 import static android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
@@ -3018,6 +3019,52 @@
     }
 
     @Test
+    public void testDomainSelectionListenOriginalConnectionPropertiesChange() throws Exception {
+        setupForCallTest();
+
+        int selectedDomain = DOMAIN_PS;
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+        verify(mDomainSelectionResolver)
+                .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
+        verify(mEmergencyStateTracker)
+                .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+        verify(mPhone0).dial(anyString(), any(), any());
+
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        c.setTelecomCallId(TELECOM_CALL_ID1);
+        c.setIsImsConnection(true);
+        Connection orgConn = c.getOriginalConnection();
+        doReturn(PhoneConstants.PHONE_TYPE_IMS).when(orgConn).getPhoneType();
+
+        TelephonyConnection.TelephonyConnectionListener connectionListener =
+                mTestConnectionService.getEmergencyConnectionListener();
+
+        doReturn(Call.State.DISCONNECTING).when(orgConn).getState();
+        connectionListener.onConnectionPropertiesChanged(c, PROPERTY_WIFI);
+
+        verify(mEmergencyStateTracker, times(0)).onEmergencyCallPropertiesChanged(
+                anyInt(), anyString());
+
+        doReturn(Call.State.ACTIVE).when(orgConn).getState();
+        connectionListener.onConnectionPropertiesChanged(c, PROPERTY_WIFI);
+
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallPropertiesChanged(
+                eq(PROPERTY_WIFI), eq(TELECOM_CALL_ID1));
+
+        connectionListener.onConnectionPropertiesChanged(c, 0);
+
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallPropertiesChanged(
+                eq(0), eq(TELECOM_CALL_ID1));
+    }
+
+    @Test
     public void testDomainSelectionTempFailure() throws Exception {
         setupForCallTest();