Merge "Don't load cached geofence result from persisted memory when booting" into main
diff --git a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
index 8d49634..aedd06e 100644
--- a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
@@ -35,6 +35,7 @@
 import android.telephony.ims.ImsReasonInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CallFailCause;
 
 /**
  * Implements domain selector for outgoing non-emergency calls.
@@ -325,33 +326,49 @@
         }
 
         // Check if this is a re-dial scenario
-        // IMS -> CS
         ImsReasonInfo imsReasonInfo = mSelectionAttributes.getPsDisconnectCause();
-        if (mReselectDomain && imsReasonInfo != null) {
-            logd("PsDisconnectCause:" + imsReasonInfo.getCode());
+        if (mReselectDomain) {
             mReselectDomain = false;
-            if (imsReasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED) {
-                if (isOutOfService()) {
-                    loge("Cannot place call in current ServiceState: " + mServiceState.getState());
-                    notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
-                } else {
-                    logd("Redialing over CS");
-                    notifyCsSelected();
-                }
-                return;
-            } else {
-                logd("Redialing cancelled.");
-                // Not a valid redial
-                notifySelectionTerminated(DisconnectCause.NOT_VALID);
+
+            // Out of service
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+
                 return;
             }
-        }
 
-        // CS -> IMS
-        // TODO: @PreciseDisconnectCauses doesn't contain cause code related to redial on IMS.
-        if (mReselectDomain /*mSelectionAttributes.getCsDisconnectCause() == IMS_REDIAL_CODE*/) {
-            logd("Redialing cancelled.");
+            // IMS -> CS
+            if (imsReasonInfo != null) {
+                logd("PsDisconnectCause:" + imsReasonInfo.getCode());
+                if (imsReasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED) {
+                    logd("Redialing over CS");
+                    notifyCsSelected();
+                } else {
+                    // Not a valid redial
+                    logd("Redialing cancelled.");
+                    notifySelectionTerminated(DisconnectCause.NOT_VALID);
+                }
+                return;
+            }
+
+            // CS -> IMS
+            int csDisconnectCause = mSelectionAttributes.getCsDisconnectCause();
+            switch (csDisconnectCause) {
+                case CallFailCause.EMC_REDIAL_ON_IMS:
+                case CallFailCause.EMC_REDIAL_ON_VOWIFI:
+                    // Check IMS registration state.
+                    if (mImsStateTracker.isImsRegistered()) {
+                        logd("IMS is registered");
+                        notifyPsSelected();
+                        return;
+                    } else {
+                        logd("IMS is NOT registered");
+                    }
+            }
+
             // Not a valid redial
+            logd("Redialing cancelled.");
             notifySelectionTerminated(DisconnectCause.NOT_VALID);
             return;
         }
diff --git a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
index 7f2f026..43bb1c5 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
@@ -130,6 +130,18 @@
             android:layout_height="wrap_content"
             android:paddingRight="4dp"
             android:text="@string/getSatellitePlmnsForCarrier"/>
+        <Button
+            android:id="@+id/registerForCarrierRoamingNtnModeChanged"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/registerForCarrierRoamingNtnModeChanged"/>
+        <Button
+            android:id="@+id/unregisterForCarrierRoamingNtnModeChanged"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/unregisterForCarrierRoamingNtnModeChanged"/>
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
index df2aaf7..e7fbb97 100644
--- a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
+++ b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
@@ -93,4 +93,7 @@
 
     <string name="Back">Back</string>
     <string name="ClearLog">Clear Log</string>
+
+    <string name="registerForCarrierRoamingNtnModeChanged">registerForCarrierRoamingNtnModeChanged</string>
+    <string name="unregisterForCarrierRoamingNtnModeChanged">unregisterForCarrierRoamingNtnModeChanged</string>
 </resources>
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
index 27967f4..93a8131 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
@@ -23,6 +23,7 @@
 import android.os.OutcomeReceiver;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.satellite.wrapper.CarrierRoamingNtnModeListenerWrapper;
 import android.telephony.satellite.wrapper.NtnSignalStrengthCallbackWrapper;
 import android.telephony.satellite.wrapper.NtnSignalStrengthWrapper;
 import android.telephony.satellite.wrapper.SatelliteCapabilitiesCallbackWrapper;
@@ -53,6 +54,7 @@
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
     private SatelliteManagerWrapper mSatelliteManagerWrapper;
     private NtnSignalStrengthCallback mNtnSignalStrengthCallback = null;
+    private CarrierRoamingNtnModeListener mCarrierRoamingNtnModeListener = null;
     private SatelliteCapabilitiesCallbackWrapper mSatelliteCapabilitiesCallback;
     private SubscriptionManager mSubscriptionManager;
     private int mSubId;
@@ -99,6 +101,10 @@
                 .setOnClickListener(this::getAttachRestrictionReasonsForCarrier);
         findViewById(R.id.getSatellitePlmnsForCarrier)
                 .setOnClickListener(this::getSatellitePlmnsForCarrier);
+        findViewById(R.id.registerForCarrierRoamingNtnModeChanged)
+                .setOnClickListener(this::registerForCarrierRoamingNtnModeChanged);
+        findViewById(R.id.unregisterForCarrierRoamingNtnModeChanged)
+                .setOnClickListener(this::unregisterForCarrierRoamingNtnModeChanged);
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -180,6 +186,39 @@
         }
     }
 
+    private void registerForCarrierRoamingNtnModeChanged(View view) {
+        addLogMessage("registerForCarrierRoamingNtnModeChanged");
+        logd("registerForCarrierRoamingNtnModeChanged()");
+        if (mCarrierRoamingNtnModeListener == null) {
+            logd("Creating new CarrierRoamingNtnModeListener instance.");
+            mCarrierRoamingNtnModeListener = new CarrierRoamingNtnModeListener();
+        }
+
+        try {
+            mSatelliteManagerWrapper.registerForCarrierRoamingNtnModeChanged(mSubId, mExecutor,
+                    mCarrierRoamingNtnModeListener);
+        } catch (Exception ex) {
+            String errorMessage = "registerForCarrierRoamingNtnModeChanged: " + ex.getMessage();
+            logd(errorMessage);
+            addLogMessage(errorMessage);
+            mCarrierRoamingNtnModeListener = null;
+        }
+    }
+
+    private void unregisterForCarrierRoamingNtnModeChanged(View view) {
+        addLogMessage("unregisterForCarrierRoamingNtnModeChanged");
+        logd("unregisterForCarrierRoamingNtnModeChanged()");
+        if (mCarrierRoamingNtnModeListener != null) {
+            mSatelliteManagerWrapper.unregisterForCarrierRoamingNtnModeChanged(mSubId,
+                    mCarrierRoamingNtnModeListener);
+            mCarrierRoamingNtnModeListener = null;
+            addLogMessage("mCarrierRoamingNtnModeListener was unregistered");
+        } else {
+            addLogMessage("mCarrierRoamingNtnModeListener is null, ignored.");
+        }
+    }
+
+
     private void registerForNtnSignalStrengthChanged(View view) {
         addLogMessage("registerForNtnSignalStrengthChanged");
         logd("registerForNtnSignalStrengthChanged()");
@@ -285,6 +324,16 @@
         }
     }
 
+    private class CarrierRoamingNtnModeListener implements CarrierRoamingNtnModeListenerWrapper {
+
+        @Override
+        public void onCarrierRoamingNtnModeChanged(boolean active) {
+            String message = "Received onCarrierRoamingNtnModeChanged active: " + active;
+            logd(message);
+            addLogMessage(message);
+        }
+    }
+
     private void isNonTerrestrialNetwork(View view) {
         boolean isNonTerrestrialNetwork = mSatelliteManagerWrapper.isNonTerrestrialNetwork(mSubId);
         addLogMessage("isNonTerrestrialNetwork=" + isNonTerrestrialNetwork);
diff --git a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
index 309418e..cf5f8e9 100644
--- a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
@@ -53,6 +53,8 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.telephony.CallFailCause;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -446,7 +448,6 @@
                 .setEmergency(false)
                 .setVideoCall(false)
                 .setExitedFromAirplaneMode(false)
-                .setPsDisconnectCause(imsReasonInfoCsRetry)
                 .build();
 
         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
@@ -590,6 +591,82 @@
                 mNormalCallDomainSelector.getSelectorState());
     }
 
+    @Test
+    public void testEmcCsFailureAndPsRedial() {
+        final TestTransportSelectorCallback transportSelectorCallback =
+                new TestTransportSelectorCallback(mNormalCallDomainSelector);
+
+        final ServiceState serviceState = new ServiceState();
+
+        // dial CS call
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, false, false, false, false);
+        NetworkRegistrationInfo nwRegistrationInfo = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
+                AccessNetworkConstants.AccessNetworkType.UTRAN, 0, false,
+                null, null, null, false, 0, 0, 0);
+        serviceState.addNetworkRegistrationInfo(nwRegistrationInfo);
+        DomainSelectionService.SelectionAttributes attributes =
+                new DomainSelectionService.SelectionAttributes.Builder(
+                        SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setAddress(TEST_URI)
+                        .setCallId(TEST_CALLID)
+                        .setEmergency(false)
+                        .setVideoCall(false)
+                        .setExitedFromAirplaneMode(false)
+                        .build();
+
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+
+        processAllMessages();
+        assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_CS);
+        assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
+                mNormalCallDomainSelector.getSelectorState());
+
+        // EMC_REDIAL_ON_IMS
+        transportSelectorCallback.reset();
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, false, true, false);
+        attributes = new DomainSelectionService.SelectionAttributes.Builder(
+                SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
+                .setCallId(TEST_CALLID)
+                .setEmergency(false)
+                .setVideoCall(false)
+                .setExitedFromAirplaneMode(false)
+                .setCsDisconnectCause(CallFailCause.EMC_REDIAL_ON_IMS)
+                .build();
+
+        mNormalCallDomainSelector.reselectDomain(attributes);
+
+        processAllMessages();
+        assertTrue(transportSelectorCallback.mWwanSelected);
+        assertEquals(NetworkRegistrationInfo.DOMAIN_PS, transportSelectorCallback.mSelectedDomain);
+        assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
+                mNormalCallDomainSelector.getSelectorState());
+
+        // EMC_REDIAL_ON_VOWIFI
+        transportSelectorCallback.reset();
+        initialize(serviceState, true, true, true, false);
+        attributes = new DomainSelectionService.SelectionAttributes.Builder(
+                SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
+                .setCallId(TEST_CALLID)
+                .setEmergency(false)
+                .setVideoCall(false)
+                .setExitedFromAirplaneMode(false)
+                .setCsDisconnectCause(CallFailCause.EMC_REDIAL_ON_VOWIFI)
+                .build();
+
+        mNormalCallDomainSelector.reselectDomain(attributes);
+
+        processAllMessages();
+        assertTrue(transportSelectorCallback.mWlanSelected);
+        assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
+                mNormalCallDomainSelector.getSelectorState());
+    }
+
     static class TestTransportSelectorCallback implements TransportSelectorCallback,
             WwanSelectorCallback {
         public boolean mCreated;
@@ -655,6 +732,7 @@
             Log.i(TAG, "onDomainSelected - called");
             mSelectedDomain = domain;
             mDomainSelected = true;
+            mWwanSelected = true;
 
             assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
                     mNormalCallDomainSelector.getSelectorState());