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

Commit 45859865 authored by joonhunshin's avatar joonhunshin
Browse files

Disable satellite when cellular modem enabled in Idle state

Bug: 361250450
Test: atest SatelliteSesssionController
      completed demo mode test
      regression test b/366397074
Flag: com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn
Change-Id: I6a18d5ba96d6b978b9eda178999ece8ce89c2abb
parent 98813474
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -4818,6 +4818,17 @@ public class SatelliteController extends Handler {
        return getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
    }

    /**
     * Return whether the device allows to turn off satellite session for emergency call.
     *
     * @param subId Associated subscription ID
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public boolean turnOffSatelliteSessionForEmergencyCall(int subId) {
        return getConfigForSubId(subId).getBoolean(
                KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL);
    }

    private int getCarrierRoamingNtnConnectType(int subId) {
        return getConfigForSubId(subId).getInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT);
    }
+120 −5
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.os.RemoteException;
import android.os.SystemProperties;
import android.telephony.DropBoxManagerLoggerBackend;
import android.telephony.PersistentLogger;
import android.telephony.ServiceState;
import android.telephony.satellite.ISatelliteModemStateCallback;
import android.telephony.satellite.SatelliteManager;
import android.telephony.satellite.stub.ISatelliteGateway;
@@ -66,6 +67,7 @@ import com.android.internal.telephony.DeviceStateMonitor;
import com.android.internal.telephony.ExponentialBackoff;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
import com.android.internal.util.State;
@@ -124,6 +126,8 @@ public class SatelliteSessionController extends StateMachine {
    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 int EVENT_ENABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE = 12;
    private static final int EVENT_SERVICE_STATE_CHANGED = 13;

    private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds
    private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute
@@ -277,13 +281,27 @@ public class SatelliteSessionController extends StateMachine {
            bindService();
        });

        Phone phone = mSatelliteController.getSatellitePhone();
        if (phone == null) {
            phone = SatelliteServiceUtils.getPhone();
        Phone satellitePhone = mSatelliteController.getSatellitePhone();
        if (satellitePhone == null) {
            satellitePhone = SatelliteServiceUtils.getPhone();
        }
        mDeviceStateMonitor = phone.getDeviceStateMonitor();
        mDeviceStateMonitor = satellitePhone.getDeviceStateMonitor();
        mSessionMetricsStats = SessionMetricsStats.getInstance();

        if (mFeatureFlags.carrierRoamingNbIotNtn()) {
            // Register to received Cellular service state
            for (Phone phone : PhoneFactory.getPhones()) {
                if (phone == null) continue;

                phone.registerForServiceStateChanged(
                        getHandler(), EVENT_SERVICE_STATE_CHANGED, null);
                if (DBG) {
                    plogd("SatelliteSessionController: registerForServiceStateChanged phoneId "
                            + phone.getPhoneId());
                }
            }
        }

        addState(mUnavailableState);
        addState(mPowerOffState);
        addState(mEnablingState);
@@ -547,9 +565,33 @@ public class SatelliteSessionController extends StateMachine {
        plogd("cleanUpResource");
        mIsDeviceAlignedWithSatellite = false;
        unregisterForScreenStateChanged();

        if (mFeatureFlags.carrierRoamingNbIotNtn()) {
            // Register to received Cellular service state
            for (Phone phone : PhoneFactory.getPhones()) {
                if (phone == null) continue;

                phone.unregisterForServiceStateChanged(getHandler());
                if (DBG) {
                    plogd("cleanUpResource: unregisterForServiceStateChanged phoneId "
                            + phone.getPhoneId());
                }
            }
        }

        quitNow();
    }

    /**
     * Uses this function to notify that cellular service state has changed
     *
     * @param serviceState The state of the cellular service.
     */
    @VisibleForTesting
    public void onCellularServiceStateChanged(ServiceState serviceState) {
        sendMessage(EVENT_SERVICE_STATE_CHANGED, new AsyncResult(null, serviceState, null));
    }

    private boolean isDemoMode() {
        return mIsDemoMode;
    }
@@ -790,8 +832,11 @@ public class SatelliteSessionController extends StateMachine {
            mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE;
            mIsSendingTriggeredDuringTransferringState.set(false);
            stopNbIotInactivityTimer();

            //Enable Cellular Modem scanning
            mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, null);
            Message onCompleted =
                    obtainMessage(EVENT_ENABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE);
            mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, onCompleted);
            notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
        }

@@ -821,6 +866,18 @@ public class SatelliteSessionController extends StateMachine {
                case EVENT_SATELLITE_MODEM_STATE_CHANGED:
                    handleSatelliteModemStateChanged(msg);
                    break;
                case EVENT_ENABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE:
                    handleEventEnableCellularModemWhileSatelliteModeIsOnDone();
                    break;
                case EVENT_SERVICE_STATE_CHANGED:
                    AsyncResult ar = (msg.obj != null) ? (AsyncResult) msg.obj : null;
                    if (ar == null || ar.result == null) {
                        plogd("IdleState: processing: can't access ServiceState");
                    } else {
                        ServiceState newServiceState = (ServiceState) ar.result;
                        handleEventServiceStateChanged(newServiceState);
                    }
                    break;
            }
            // Ignore all unexpected events.
            return HANDLED;
@@ -848,6 +905,58 @@ public class SatelliteSessionController extends StateMachine {
            }
        }

        private void handleEventEnableCellularModemWhileSatelliteModeIsOnDone() {
            if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
                Rlog.d(TAG, "handleEventEnableCellularModemWhileSatelliteModeIsOnDone: "
                        + "carrierRoamingNbIotNtn is disabled");
                return;
            }

            ServiceState serviceState = mSatelliteController.getSatellitePhone().getServiceState();
            if (serviceState == null) {
                plogd("handleEventEnableCellularModemWhileSatelliteModeIsOnDone: "
                        + "can't access ServiceState");
                return;
            }
            handleEventServiceStateChanged(serviceState);
        }

        private void handleEventServiceStateChanged(ServiceState serviceState) {
            boolean isInServiceOrEmergency =
                    serviceState.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
                    || serviceState.getDataRegState() == ServiceState.STATE_IN_SERVICE
                    || serviceState.isEmergencyOnly();
            if (!isInServiceOrEmergency) {
                plogd("handleEventServiceStateChanged: is not IN_SERVICE or EMERGENCY_ONLY");
                return;
            }

            // In emergency
            boolean isEmergency = mSatelliteController.getRequestIsEmergency();
            if (isEmergency) {
                boolean isEmergencyCommunicationEstablished = (mDatagramController == null)
                        ? false : mDatagramController.isEmergencyCommunicationEstablished();
                boolean isTurnOffAllowed =
                        mSatelliteController.turnOffSatelliteSessionForEmergencyCall(getSubId());
                if (isEmergencyCommunicationEstablished || !isTurnOffAllowed) {
                    logd("handleEventServiceStateChanged: "
                            + "can't disable emergency satellite session");
                    return;
                }
            }

            mSatelliteController.requestSatelliteEnabled(
                    false /*enableSatellite*/,
                    false /*enableDemoMode*/,
                    isEmergency /*isEmergency*/,
                    new IIntegerConsumer.Stub() {
                        @Override
                        public void accept(int result) {
                            plogd("requestSatelliteEnabled result=" + result);
                        }
                    });
        }

        private void handleEventDisableCellularModemWhileSatelliteModeIsOnDone(
                @NonNull AsyncResult result) {
            synchronized (mLock) {
@@ -1232,6 +1341,12 @@ public class SatelliteSessionController extends StateMachine {
            case EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
                whatString = "EVENT_CARRIER_ROAMING_NB_IOT_INACTIVITY_TIMER_TIMED_OUT";
                break;
            case EVENT_ENABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE:
                whatString = "EVENT_ENABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE";
                break;
            case EVENT_SERVICE_STATE_CHANGED:
                whatString = "EVENT_SERVICE_STATE_CHANGED";
                break;
            default:
                whatString = "UNKNOWN EVENT " + what;
        }
+86 −1
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.telephony.ServiceState;
import android.telephony.satellite.ISatelliteModemStateCallback;
import android.telephony.satellite.SatelliteManager;
import android.testing.AndroidTestingRunner;
@@ -104,6 +105,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
    @Mock private DatagramReceiver mMockDatagramReceiver;
    @Mock private DatagramDispatcher mMockDatagramDispatcher;
    @Mock private DatagramController mMockDatagramController;
    @Mock private ServiceState mMockServiceState;

    @Captor ArgumentCaptor<Handler> mHandlerCaptor;
    @Captor ArgumentCaptor<Integer> mMsgCaptor;
@@ -216,6 +218,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
        // Notify Screen off
        sendScreenStateChanged(mHandlerCaptor.getValue(), mMsgCaptor.getValue(), false);
        processAllMessages();
        clearInvocations(mMockSatelliteController);

        // Verify that the screen off inactivity timer is started.
        assertTrue(mTestSatelliteSessionController.isScreenOffInActivityTimerStarted());
@@ -283,6 +286,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
        doNothing().when(mDeviceStateMonitor).registerForScreenStateChanged(
                eq(mTestSatelliteSessionController.getHandler()), anyInt(), any());
        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);
        when(mMockSatelliteController.turnOffSatelliteSessionForEmergencyCall(
                anyInt())).thenReturn(false);

        when(mMockSatelliteController.getRequestIsEmergency()).thenReturn(false);
        when(mMockSatelliteController.isSatelliteRoamingP2pSmSSupported(
@@ -295,6 +300,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest {

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

@@ -328,6 +334,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
        doNothing().when(mDeviceStateMonitor).registerForScreenStateChanged(
                eq(mTestSatelliteSessionController.getHandler()), anyInt(), any());
        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);
        when(mMockSatelliteController.turnOffSatelliteSessionForEmergencyCall(
                anyInt())).thenReturn(false);

        when(mMockSatelliteController.getRequestIsEmergency()).thenReturn(true);
        when(mMockSatelliteController.isSatelliteEsosSupported(anyInt())).thenReturn(true);
@@ -338,6 +346,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest {

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

@@ -365,6 +374,76 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
                mTestSatelliteModemStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
    }

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

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

        // Conditions for operation
        boolean isEmergency = true;
        // Cellular network is not IN_SERVICE and emergency only.
        // Satellite request is emergency and emergency communication was established.
        // Disabling satellite was not allowed
        when(mMockServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
        when(mMockServiceState.getDataRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
        when(mMockServiceState.isEmergencyOnly()).thenReturn(false);
        when(mMockSatelliteController.getRequestIsEmergency()).thenReturn(isEmergency);
        when(mMockDatagramController.isEmergencyCommunicationEstablished()).thenReturn(true);
        when(mMockSatelliteController.turnOffSatelliteSessionForEmergencyCall(
                anyInt())).thenReturn(false);

        moveToIdleState();

        // Cellular network is not in STATE_IN_SERVICE or emergency only.
        // Should not disable satellite
        verify(mMockSatelliteController, never()).requestSatelliteEnabled(
                eq(false), eq(false), eq(isEmergency), any(IIntegerConsumer.Stub.class));

        // Notify cellular service is in STATE_IN_SERVICE.
        ServiceState serviceState = new ServiceState();
        serviceState.setVoiceRegState(ServiceState.STATE_IN_SERVICE);
        serviceState.setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
        serviceState.setEmergencyOnly(false);
        mTestSatelliteSessionController.onCellularServiceStateChanged(serviceState);
        processAllMessages();

        // Satellite is in emergency mode and emergency communication was established.
        // Should not disable satellite
        verify(mMockSatelliteController, never()).requestSatelliteEnabled(
                eq(false), eq(false), eq(isEmergency), any(IIntegerConsumer.Stub.class));

        // Satellite is in emergency mode but emergency communication was not established.
        // Disabling satellite was not allowed
        when(mMockDatagramController.isEmergencyCommunicationEstablished()).thenReturn(false);
        when(mMockSatelliteController.turnOffSatelliteSessionForEmergencyCall(
                anyInt())).thenReturn(false);
        mTestSatelliteSessionController.onCellularServiceStateChanged(serviceState);
        processAllMessages();

        // Should not disable satellite
        verify(mMockSatelliteController, never()).requestSatelliteEnabled(
                eq(false), eq(false), eq(isEmergency), any(IIntegerConsumer.Stub.class));

        // Satellite is in emergency mode but emergency communication was not established.
        // Disabling satellite was allowed
        when(mMockSatelliteController.turnOffSatelliteSessionForEmergencyCall(
                anyInt())).thenReturn(true);
        mTestSatelliteSessionController.onCellularServiceStateChanged(serviceState);
        processAllMessages();

        // Should disable satellite
        verify(mMockSatelliteController).requestSatelliteEnabled(
                eq(false), eq(false), eq(isEmergency), any(IIntegerConsumer.Stub.class));
    }

    @Test
    public void testStateTransition() {
        /**
@@ -1419,6 +1498,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
    }

    private static class TestSatelliteSessionController extends SatelliteSessionController {
        boolean mSatelliteEnabledForNtnOnlySubscription = true;

        TestSatelliteSessionController(Context context, Looper looper, FeatureFlags featureFlags,
                boolean isSatelliteSupported,
                SatelliteModemInterface satelliteModemInterface) {
@@ -1450,7 +1531,11 @@ public class SatelliteSessionControllerTest extends TelephonyTest {
        }

        protected boolean isSatelliteEnabledForNtnOnlySubscription() {
            return true;
            return mSatelliteEnabledForNtnOnlySubscription;
        }

        void setSatelliteEnabledForNtnOnlySubscription(boolean enabled) {
            mSatelliteEnabledForNtnOnlySubscription = false;
        }
    }