Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70f83924 authored by joonhunshin's avatar joonhunshin
Browse files

Idle mode scanning for terrestrial network when P2P SMS or ESOS mode inactivity timer expired

Bug: 350516253
Test: atest SatelliteSessionControllerTest, SatelliteControllerTest
Flag: com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn
Change-Id: I65951e74c531c04027a5bd10d059658559ae4c9c
parent 6db10297
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -29,8 +29,11 @@ import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUP
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_NIDD_APN_NAME_STRING;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER;
import static android.telephony.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
@@ -2378,6 +2381,12 @@ public class SatelliteController extends Handler {

        DemoSimulator.getInstance().setDeviceAlignedWithSatellite(isAligned);
        mDatagramController.setDeviceAlignedWithSatellite(isAligned);
        if (mSatelliteSessionController != null) {
            mSatelliteSessionController.setDeviceAlignedWithSatellite(isAligned);
        } else {
            ploge("setDeviceAlignedWithSatellite: mSatelliteSessionController"
                    + " is not initialized yet");
        }
    }

    /**
@@ -4327,11 +4336,14 @@ public class SatelliteController extends Handler {
                    KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL,
                    KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
                    KEY_SATELLITE_ESOS_SUPPORTED_BOOL,
                    KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL,
                    KEY_SATELLITE_NIDD_APN_NAME_STRING,
                    KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT,
                    KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT,
                    KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT,
                    KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT
                    KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT,
                    KEY_SATELLITE_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT,
                    KEY_SATELLITE_ESOS_INACTIVITY_TIMEOUT_SEC_INT
            );
        }
        if (config == null || config.isEmpty()) {
@@ -4462,7 +4474,23 @@ public class SatelliteController extends Handler {
                .getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL);
    }

    private boolean isSatelliteEsosSupported(int subId) {
    /**
     * Return whether the device support P2P SMS mode from carrier config.
     *
     * @param subId Associated subscription ID
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public boolean isSatelliteRoamingP2pSmSSupported(int subId) {
        return getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL);
    }

    /**
     * Return whether the device support ESOS mode from carrier config.
     *
     * @param subId Associated subscription ID
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public boolean isSatelliteEsosSupported(int subId) {
        return getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
    }

@@ -4983,7 +5011,7 @@ public class SatelliteController extends Handler {
        synchronized (mSatelliteViaOemProvisionLock) {
            plogd("persistOemEnabledSatelliteProvisionStatus: isProvisioned=" + isProvisioned);
            if (mFeatureFlags.carrierRoamingNbIotNtn()) {
                int subId = SatelliteServiceUtils.getOemBasedNonTerrestrialSubscriptionId(mContext);
                int subId = SatelliteServiceUtils.getNtnOnlySubscriptionId(mContext);
                if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                    try {
                        mSubscriptionManagerService.setIsSatelliteProvisionedForNonIpDatagram(subId,
@@ -5014,7 +5042,7 @@ public class SatelliteController extends Handler {
        plogd("getPersistedOemEnabledSatelliteProvisionStatus:");
        synchronized (mSatelliteViaOemProvisionLock) {
            if (mFeatureFlags.carrierRoamingNbIotNtn()) {
                int subId = SatelliteServiceUtils.getOemBasedNonTerrestrialSubscriptionId(mContext);
                int subId = SatelliteServiceUtils.getNtnOnlySubscriptionId(mContext);
                if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                    return mSubscriptionManagerService.isSatelliteProvisionedForNonIpDatagram(
                            subId);
+2 −2
Original line number Diff line number Diff line
@@ -348,7 +348,7 @@ public class SatelliteServiceUtils {
     * @return ID of the subscription that supports OEM-based satellite if any,
     * return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} otherwise.
     */
    public static int getOemBasedNonTerrestrialSubscriptionId(@NonNull Context context) {
    public static int getNtnOnlySubscriptionId(@NonNull Context context) {
        List<SubscriptionInfo> infoList =
                SubscriptionManagerService.getInstance().getAllSubInfoList(
                        context.getOpPackageName(), null);
@@ -358,7 +358,7 @@ public class SatelliteServiceUtils {
                .mapToInt(SubscriptionInfo::getSubscriptionId)
                .findFirst()
                .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        logd("getOemBasedNonTerrestrialSubscriptionId: subId=" + subId);
        logd("getNtnOnlySubscriptionId: subId=" + subId);
        return subId;
    }

+146 −6
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.internal.telephony.satellite;

import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED;
@@ -113,15 +115,17 @@ public class SatelliteSessionController extends StateMachine {
    private static final int EVENT_SATELLITE_ENABLEMENT_FAILED = 8;
    private static final int EVENT_SCREEN_STATE_CHANGED = 9;
    protected static final int EVENT_SCREEN_OFF_INACTIVITY_TIMER_TIMED_OUT = 10;
    protected static final int EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT = 11;

    private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds
    private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute
    private static final int REBIND_MULTIPLIER = 2;
    private static final int DEFAULT_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC = 30;
    private static final int DEFAULT_P2P_SMS_INACTIVITY_TIMEOUT_SEC = 180;
    private static final int DEFAULT_ESOS_INACTIVITY_TIMEOUT_SEC = 600;

    @NonNull private final ExponentialBackoff mExponentialBackoff;
    @NonNull private final Object mLock = new Object();
    @NonNull private final Phone mPhone;
    @Nullable
    private ISatelliteGateway mSatelliteGatewayService;
    private String mSatelliteGatewayServicePackageName = "";
@@ -155,6 +159,8 @@ public class SatelliteSessionController extends StateMachine {
    private boolean mIsDemoMode = false;
    // Interested in screen off, so use default value true
    boolean mIsScreenOn = true;
    private boolean mIsDeviceAlignedWithSatellite = false;

    @GuardedBy("mLock")
    @NonNull private boolean mIsDisableCellularModemInProgress = false;
    @NonNull private final SatelliteController mSatelliteController;
@@ -256,8 +262,11 @@ public class SatelliteSessionController extends StateMachine {
            bindService();
        });

        mPhone = SatelliteServiceUtils.getPhone();
        mDeviceStateMonitor = mPhone.getDeviceStateMonitor();
        Phone phone = mSatelliteController.getSatellitePhone();
        if (phone == null) {
            phone = SatelliteServiceUtils.getPhone();
        }
        mDeviceStateMonitor = phone.getDeviceStateMonitor();

        addState(mUnavailableState);
        addState(mPowerOffState);
@@ -469,6 +478,29 @@ public class SatelliteSessionController extends StateMachine {
        mIsDemoMode = isDemoMode;
    }

    /**
     * Notify whether the device is aligned with the satellite
     *
     * @param isAligned {@code true} Device is aligned with the satellite,
     *                  {@code false} otherwise.
     */
    public void setDeviceAlignedWithSatellite(boolean isAligned) {
        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
            plogd("setDeviceAlignedWithSatellite: carrierRoamingNbIotNtn is disabled");
            return;
        }

        mIsDeviceAlignedWithSatellite = isAligned;

        if (mIsDeviceAlignedWithSatellite) {
            stopCarrierRoamingNbIotInactivityTimer();
        } else {
            if (mCurrentState == SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED) {
                evaluateStartingCarrierRoamingNbIotInactivityTimer();
            }
        }
    }

    /**
     * Get whether state machine is in enabling state.
     *
@@ -485,6 +517,7 @@ public class SatelliteSessionController extends StateMachine {
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    public void cleanUpResource() {
        if (DBG) plogd("cleanUpResource");
        mIsDeviceAlignedWithSatellite = false;
        unregisterForScreenStateChanged();
    }

@@ -929,11 +962,14 @@ public class SatelliteSessionController extends StateMachine {
            mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED;
            notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
            startNbIotInactivityTimer();
            evaluateStartingCarrierRoamingNbIotInactivityTimer();
        }

        @Override
        public void exit() {
            if (DBG) plogd("Exiting NotConnectedState");

            stopCarrierRoamingNbIotInactivityTimer();
        }

        @Override
@@ -947,6 +983,8 @@ public class SatelliteSessionController extends StateMachine {
                case EVENT_SATELLITE_MODEM_STATE_CHANGED:
                    handleEventSatelliteModemStateChanged(msg.arg1);
                    break;
                case EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
                    // fall through
                case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
                    transitionTo(mIdleState);
                    break;
@@ -981,13 +1019,17 @@ public class SatelliteSessionController extends StateMachine {
                    || datagramTransferState.receiveState
                    == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT) {
                stopNbIotInactivityTimer();
                stopCarrierRoamingNbIotInactivityTimer();
            } else if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE
                    && datagramTransferState.receiveState
                    == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
                startNbIotInactivityTimer();
                evaluateStartingCarrierRoamingNbIotInactivityTimer();
            } else if (isSending(datagramTransferState.sendState)
                    || isReceiving(datagramTransferState.receiveState)) {
                restartNbIotInactivityTimer();
                stopCarrierRoamingNbIotInactivityTimer();
                evaluateStartingCarrierRoamingNbIotInactivityTimer();
            }
        }
    }
@@ -1092,6 +1134,9 @@ public class SatelliteSessionController extends StateMachine {
            case EVENT_SCREEN_OFF_INACTIVITY_TIMER_TIMED_OUT:
                whatString = "EVENT_SCREEN_OFF_INACTIVITY_TIMER_TIMED_OUT";
                break;
            case EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
                whatString = "EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT";
                break;
            default:
                whatString = "UNKNOWN EVENT " + what;
        }
@@ -1106,6 +1151,15 @@ public class SatelliteSessionController extends StateMachine {
        }
    }

    private int getSubId() {
        Phone phone = mSatelliteController.getSatellitePhone();
        if (phone == null) {
            return SatelliteServiceUtils.getPhone().getSubId();
        }

        return phone.getSubId();
    }

    private void notifyStateChangedEvent(@SatelliteManager.SatelliteModemState int state) {
        mDatagramController.onSatelliteModemStateChanged(state);

@@ -1324,17 +1378,85 @@ public class SatelliteSessionController extends StateMachine {
    }

    private int getScreenOffInactivityTimeoutDurationSec() {
        PersistableBundle config = mSatelliteController.getPersistableBundle(
                mPhone.getSubId());
        PersistableBundle config = mSatelliteController.getPersistableBundle(getSubId());

        return config.getInt(KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT,
                DEFAULT_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC);
    }

    private int getP2pSmsInactivityTimeoutDurationSec() {
        PersistableBundle config = mSatelliteController.getPersistableBundle(getSubId());

        return config.getInt(KEY_SATELLITE_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT,
                DEFAULT_P2P_SMS_INACTIVITY_TIMEOUT_SEC);
    }

    private int getEsosInactivityTimeoutDurationSec() {
        PersistableBundle config = mSatelliteController.getPersistableBundle(getSubId());

        return config.getInt(KEY_SATELLITE_ESOS_INACTIVITY_TIMEOUT_SEC_INT,
                DEFAULT_ESOS_INACTIVITY_TIMEOUT_SEC);
    }

    private void evaluateStartingCarrierRoamingNbIotInactivityTimer() {
        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
            plogd("evaluateStartingCarrierRoamingNbIotInactivityTimer: "
                    + "carrierRoamingNbIotNtn is disabled");
            return;
        }

        int subId = getSubId();
        if (!mSatelliteController.isSatelliteRoamingP2pSmSSupported(subId)
                && !mSatelliteController.isSatelliteEsosSupported(subId)) {
            plogd("evaluateStartingCarrierRoamingNbIotInactivityTimer: "
                    + "device does not support P2P SMS and ESOS are disabled");
            return;
        }

        if (mIsDeviceAlignedWithSatellite) {
            plogd("evaluateStartingCarrierRoamingNbIotInactivityTimer: "
                    + "can't start inactivity timer due to device aligned satellite");
            return;
        }

        if (hasMessages(EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT)) {
            plogd("evaluateStartingCarrierRoamingNbIotInactivityTimer: already started");
            return;
        }

        int timeOutMillis;
        if (mSatelliteController.getRequestIsEmergency()) {
            timeOutMillis = getEsosInactivityTimeoutDurationSec() * 1000;
        } else if (mSatelliteController.isInCarrierRoamingNbIotNtn()) {
            timeOutMillis = getP2pSmsInactivityTimeoutDurationSec() * 1000;
        } else {
            plogd("evaluateStartingCarrierRoamingNbIotInactivityTimer: "
                    + "can't start inactivity timer device is in not P2P SMS and ESOS mode");
            return;
        }

        DatagramController datagramController = DatagramController.getInstance();
        if (datagramController.isSendingInIdleState()
                && datagramController.isPollingInIdleState()) {
            sendMessageDelayed(EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT,
                    timeOutMillis);
            plogd("evaluateStartingCarrierRoamingNbIotInactivityTimer: start inactivity timer "
                    + timeOutMillis);
        } else {
            plogd("evaluateStartingCarrierRoamingNbIotInactivityTimer: "
                    + "can't start inactivity timer");
        }
    }

    private void stopCarrierRoamingNbIotInactivityTimer() {
        removeMessages(EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT);
        plogd("stopCarrierRoamingNbIotInactivityTimer:");
    }

    private void handleEventScreenOffInactivityTimerTimedOut() {
        plogd("handleEventScreenOffInactivityTimerTimedOut: request disable satellite");

        mSatelliteController.requestSatelliteEnabled(mPhone.getSubId(),
        mSatelliteController.requestSatelliteEnabled(getSubId(),
                false /*enableSatellite*/,
                false /*enableDemoMode*/,
                mSatelliteController.getRequestIsEmergency() /*isEmergency*/,
@@ -1384,6 +1506,12 @@ public class SatelliteSessionController extends StateMachine {
    }

    private void startNbIotInactivityTimer() {
        if (!isSatelliteEnabledForNtnOnlySubscription()) {
            plogd("startNbIotInactivityTimer: Can't start timer "
                    + "because satellite was not enabled for OEM based NB IOT");
            return;
        }

        if (isNbIotInactivityTimerStarted()) {
            plogd("NB IOT inactivity timer is already started");
            return;
@@ -1406,6 +1534,18 @@ public class SatelliteSessionController extends StateMachine {
        return hasMessages(EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT);
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected boolean isSatelliteEnabledForNtnOnlySubscription() {
        if (SatelliteServiceUtils.getNtnOnlySubscriptionId(mContext)
                != getSubId()) {
            plogd("isSatelliteEnabledForOemBasedNbIot: highest priority satellite subscription "
                    + "is not NTN-only subscription");
            return false;
        }

        return true;
    }

    private boolean isSatellitePersistentLoggingEnabled(
            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
        if (featureFlags.satellitePersistentLogging()) {
+103 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.internal.telephony.satellite;

import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED;
@@ -94,6 +96,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
    private static final String STATE_NOT_CONNECTED = "NotConnectedState";
    private static final String STATE_CONNECTED = "ConnectedState";
    private static final int SCREEN_OFF_INACTIVITY_TIMEOUT_SEC = 30;
    private static final int P2P_SMS_INACTIVITY_TIMEOUT_SEC = 180;
    private static final int ESOS_INACTIVITY_TIMEOUT_SEC = 600;
    private TestSatelliteModemInterface mSatelliteModemInterface;
    private TestSatelliteSessionController mTestSatelliteSessionController;
    private TestSatelliteModemStateCallback mTestSatelliteModemStateCallback;
@@ -125,6 +129,10 @@ public class SatelliteSessionControllerTest extends TelephonyTest {

        when(mFeatureFlags.satellitePersistentLogging()).thenReturn(true);
        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(false);
        when(mMockSatelliteController.isSatelliteRoamingP2pSmSSupported(
                anyInt())).thenReturn(false);
        when(mMockSatelliteController.isSatelliteEsosSupported(anyInt())).thenReturn(false);
        when(mMockSatelliteController.getSatellitePhone()).thenReturn(mPhone);
        mSatelliteModemInterface = new TestSatelliteModemInterface(
                mContext, mMockSatelliteController, Looper.myLooper(), mFeatureFlags);
        mTestSatelliteSessionController = new TestSatelliteSessionController(mContext,
@@ -271,6 +279,94 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
        assertFalse(mTestSatelliteSessionController.isScreenOffInActivityTimerStarted());
    }

    @Test
    public void testP2pSmsInactivityTimer() {
        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
        doNothing().when(mDeviceStateMonitor).registerForScreenStateChanged(
                eq(mTestSatelliteSessionController.getHandler()), anyInt(), any());
        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);

        when(mMockSatelliteController.getRequestIsEmergency()).thenReturn(false);
        when(mMockSatelliteController.isSatelliteRoamingP2pSmSSupported(
                anyInt())).thenReturn(true);
        when(mMockSatelliteController.isInCarrierRoamingNbIotNtn()).thenReturn(true);
        PersistableBundle bundle = new PersistableBundle();
        bundle.putInt(KEY_SATELLITE_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT,
                P2P_SMS_INACTIVITY_TIMEOUT_SEC);
        when(mMockSatelliteController.getPersistableBundle(anyInt())).thenReturn(bundle);

        // Since satellite is supported, SatelliteSessionController should move to POWER_OFF state.
        assertNotNull(mTestSatelliteSessionController);
        assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
        setupDatagramTransferringState(true);

        moveToNotConnectedState();

        // Verify that the P2P SMS inactivity timer is started.
        assertTrue(mTestSatelliteSessionController.isCarrierRoamingNbIotInActivityTimerStarted());

        mTestSatelliteSessionController.setDeviceAlignedWithSatellite(true);

        // Verify that the P2P SMS inactivity timer is stopped.
        assertFalse(mTestSatelliteSessionController.isCarrierRoamingNbIotInActivityTimerStarted());

        mTestSatelliteSessionController.setDeviceAlignedWithSatellite(false);

        // Verify that the P2P SMS inactivity timer is started.
        assertTrue(mTestSatelliteSessionController.isCarrierRoamingNbIotInActivityTimerStarted());

        // Time shift to cause timeout
        moveTimeForward(P2P_SMS_INACTIVITY_TIMEOUT_SEC * 1000);
        processAllMessages();

        // SatelliteSessionController should move to IDLE state.
        assertSuccessfulModemStateChangedCallback(
                mTestSatelliteModemStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
    }

    @Test
    public void testEsosInactivityTimer() {
        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
        doNothing().when(mDeviceStateMonitor).registerForScreenStateChanged(
                eq(mTestSatelliteSessionController.getHandler()), anyInt(), any());
        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);

        when(mMockSatelliteController.getRequestIsEmergency()).thenReturn(true);
        when(mMockSatelliteController.isSatelliteEsosSupported(anyInt())).thenReturn(true);
        PersistableBundle bundle = new PersistableBundle();
        bundle.putInt(KEY_SATELLITE_ESOS_INACTIVITY_TIMEOUT_SEC_INT,
                ESOS_INACTIVITY_TIMEOUT_SEC);
        when(mMockSatelliteController.getPersistableBundle(anyInt())).thenReturn(bundle);

        // Since satellite is supported, SatelliteSessionController should move to POWER_OFF state.
        assertNotNull(mTestSatelliteSessionController);
        assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
        setupDatagramTransferringState(true);

        moveToNotConnectedState();

        // Verify that the ESOS inactivity timer is started.
        assertTrue(mTestSatelliteSessionController.isCarrierRoamingNbIotInActivityTimerStarted());

        mTestSatelliteSessionController.setDeviceAlignedWithSatellite(true);

        // Verify that the ESOS inactivity timer is stopped.
        assertFalse(mTestSatelliteSessionController.isCarrierRoamingNbIotInActivityTimerStarted());

        mTestSatelliteSessionController.setDeviceAlignedWithSatellite(false);

        // Verify that the ESOS inactivity timer is started.
        assertTrue(mTestSatelliteSessionController.isCarrierRoamingNbIotInActivityTimerStarted());

        // Time shift to cause timeout
        moveTimeForward(ESOS_INACTIVITY_TIMEOUT_SEC * 1000);
        processAllMessages();

        // SatelliteSessionController should move to IDLE state.
        assertSuccessfulModemStateChangedCallback(
                mTestSatelliteModemStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
    }

    @Test
    public void testStateTransition() {
        /**
@@ -1230,7 +1326,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
        assertSuccessfulModemStateChangedCallback(mTestSatelliteModemStateCallback,
                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
        assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
        assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
        verify(mMockDatagramController).onSatelliteModemStateChanged(
                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
        clearInvocations(mMockDatagramController);
@@ -1352,6 +1447,13 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
            return hasMessages(EVENT_SCREEN_OFF_INACTIVITY_TIMER_TIMED_OUT);
        }

        boolean isCarrierRoamingNbIotInActivityTimerStarted() {
            return hasMessages(EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT);
        }

        protected boolean isSatelliteEnabledForNtnOnlySubscription() {
            return true;
        }
    }

    private static class TestSatelliteModemStateCallback extends ISatelliteModemStateCallback.Stub {