Merge "Support DISABLING_SATELLITE state in satellite state machine" into 24D1-dev
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
index c9337c5..b707820 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
@@ -123,6 +123,7 @@
     @NonNull private final UnavailableState mUnavailableState = new UnavailableState();
     @NonNull private final PowerOffState mPowerOffState = new PowerOffState();
     @NonNull private final EnablingState mEnablingState = new EnablingState();
+    @NonNull private final DisablingState mDisablingState = new DisablingState();
     @NonNull private final IdleState mIdleState = new IdleState();
     @NonNull private final TransferringState mTransferringState = new TransferringState();
     @NonNull private final ListeningState mListeningState = new ListeningState();
@@ -222,6 +223,7 @@
         addState(mUnavailableState);
         addState(mPowerOffState);
         addState(mEnablingState);
+        addState(mDisablingState);
         addState(mIdleState);
         addState(mTransferringState);
         addState(mListeningState);
@@ -521,6 +523,41 @@
         }
     }
 
+    private class DisablingState extends State {
+        @Override
+        public void enter() {
+            if (DBG) logd("Entering DisablingState");
+
+            mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DISABLING_SATELLITE;
+            notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DISABLING_SATELLITE);
+        }
+
+        @Override
+        public void exit() {
+            if (DBG) logd("Exiting DisablingState");
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            if (DBG) log("DisablingState: processing " + getWhatToString(msg.what));
+            switch (msg.what) {
+                case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
+                    handleSatelliteEnabledStateChanged((boolean) msg.obj);
+                    break;
+            }
+            // Ignore all unexpected events.
+            return HANDLED;
+        }
+
+        private void handleSatelliteEnabledStateChanged(boolean on) {
+            if (on) {
+                logw("Unexpected power on event while disabling satellite");
+            } else {
+                transitionTo(mPowerOffState);
+            }
+        }
+    }
+
     private class IdleState extends State {
         @Override
         public void enter() {
@@ -547,6 +584,9 @@
                     handleEventDisableCellularModemWhileSatelliteModeIsOnDone(
                             (AsyncResult) msg.obj);
                     break;
+                case EVENT_SATELLITE_ENABLEMENT_STARTED:
+                    handleSatelliteEnablementStarted((boolean) msg.obj);
+                    break;
             }
             // Ignore all unexpected events.
             return HANDLED;
@@ -637,6 +677,9 @@
                 case EVENT_SATELLITE_MODEM_STATE_CHANGED:
                     handleEventSatelliteModemStateChange(msg.arg1);
                     break;
+                case EVENT_SATELLITE_ENABLEMENT_STARTED:
+                    handleSatelliteEnablementStarted((boolean) msg.obj);
+                    break;
             }
             // Ignore all unexpected events.
             return HANDLED;
@@ -704,6 +747,9 @@
                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
                     handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "ListeningState");
                     break;
+                case EVENT_SATELLITE_ENABLEMENT_STARTED:
+                    handleSatelliteEnablementStarted((boolean) msg.obj);
+                    break;
             }
             // Ignore all unexpected events.
             return HANDLED;
@@ -763,6 +809,9 @@
                 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
                     handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
                     break;
+                case EVENT_SATELLITE_ENABLEMENT_STARTED:
+                    handleSatelliteEnablementStarted((boolean) msg.obj);
+                    break;
             }
             // Ignore all unexpected events.
             return HANDLED;
@@ -825,6 +874,9 @@
                 case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
                     handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
                     break;
+                case EVENT_SATELLITE_ENABLEMENT_STARTED:
+                    handleSatelliteEnablementStarted((boolean) msg.obj);
+                    break;
             }
             // Ignore all unexpected events.
             return HANDLED;
@@ -1030,6 +1082,12 @@
         }
     }
 
+    private void handleSatelliteEnablementStarted(boolean enabled) {
+        if (!enabled) {
+            transitionTo(mDisablingState);
+        }
+    }
+
     private boolean isMockModemAllowed() {
         return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false));
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
index e0dad0b..f6131ea 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
@@ -72,6 +72,7 @@
     private static final String STATE_UNAVAILABLE = "UnavailableState";
     private static final String STATE_POWER_OFF = "PowerOffState";
     private static final String STATE_ENABLING_SATELLITE = "EnablingState";
+    private static final String STATE_DISABLING_SATELLITE = "DisablingState";
     private static final String STATE_IDLE = "IdleState";
     private static final String STATE_TRANSFERRING = "TransferringState";
     private static final String STATE_LISTENING = "ListeningState";
@@ -927,6 +928,62 @@
         powerOnSatelliteModem();
     }
 
+    @Test
+    public void testDisablingSatellite() {
+        // Since satellite is supported, SatelliteSessionController should move to POWER_OFF state.
+        assertNotNull(mTestSatelliteSessionController);
+        assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
+
+        // IDLE -> DISABLING
+        moveToIdleState();
+        moveSatelliteToDisablingState();
+
+        // DISABLING -> POWER_OFF
+        moveToPowerOffState();
+
+        // TRANSFERRING -> DISABLING
+        moveToIdleState();
+        moveIdleToTransferringState();
+        moveSatelliteToDisablingState();
+
+        // DISABLING -> POWER_OFF
+        moveToPowerOffState();
+
+        // LISTENING -> DISABLING
+        moveToIdleState();
+        moveIdleToTransferringState();
+        moveTransferringToListeningState();
+        moveSatelliteToDisablingState();
+
+        // DISABLING -> POWER_OFF
+        moveToPowerOffState();
+    }
+
+    @Test
+    public void testDisablingSatelliteForNblot() {
+        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);
+
+        // Since satellite is supported, SatelliteSessionController should move to POWER_OFF state.
+        assertNotNull(mTestSatelliteSessionController);
+        assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
+        setupDatagramTransferringState(false);
+
+        // NOT_CONNECTED -> DISABLING
+        moveToNotConnectedState();
+        moveSatelliteToDisablingState();
+
+        // DISABLING -> POWER_OFF
+        moveToPowerOffState();
+
+        // CONNECTED -> DISABLING
+        moveToNotConnectedState();
+        moveNotConnectedToConnectedState();
+        moveSatelliteToDisablingState();
+
+        // DISABLING -> POWER_OFF
+        moveToPowerOffState();
+    }
+
     private void setupDatagramTransferringState(boolean isTransferring) {
         when(mMockDatagramController.isSendingInIdleState()).thenReturn(isTransferring);
         when(mMockDatagramController.isPollingInIdleState()).thenReturn(isTransferring);
@@ -967,6 +1024,92 @@
         mTestSatelliteModemStateCallback.clearModemStates();
     }
 
+    private void moveToPowerOffState() {
+        mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false);
+        processAllMessages();
+
+        assertSuccessfulModemStateChangedCallback(
+                mTestSatelliteModemStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF);
+        assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
+    }
+
+    private void moveToIdleState() {
+        powerOnSatelliteModem();
+
+        // SatelliteSessionController should move to IDLE state after the modem is powered on.
+        assertSuccessfulModemStateChangedCallback(
+                mTestSatelliteModemStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
+        assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName());
+        assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState());
+    }
+
+    private void moveIdleToTransferringState() {
+        assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName());
+        // Start sending datagrams
+        mTestSatelliteSessionController.onDatagramTransferStateChanged(
+                SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+        processAllMessages();
+
+        // SatelliteSessionController should move to TRANSFERRING state.
+        assertSuccessfulModemStateChangedCallback(mTestSatelliteModemStateCallback,
+                SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
+        assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName());
+        assertTrue(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState());
+    }
+
+    private void moveTransferringToListeningState() {
+        assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName());
+        // Sending datagrams is successful and done.
+        mTestSatelliteSessionController.onDatagramTransferStateChanged(
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+        processAllMessages();
+
+        // SatelliteSessionController should move to LISTENING state.
+        assertSuccessfulModemStateChangedCallback(mTestSatelliteModemStateCallback,
+                SatelliteManager.SATELLITE_MODEM_STATE_LISTENING);
+        assertEquals(STATE_LISTENING, mTestSatelliteSessionController.getCurrentStateName());
+    }
+
+    private void moveToNotConnectedState() {
+        powerOnSatelliteModem();
+        // SatelliteSessionController should move to NOT_CONNECTED state after the satellite modem
+        // is powered on.
+        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);
+    }
+
+    private void moveNotConnectedToConnectedState() {
+        // Satellite modem is connected to a satellite network.
+        mTestSatelliteSessionController.onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        processAllMessages();
+
+        // SatelliteSessionController should move to CONNECTED state
+        assertSuccessfulModemStateChangedCallback(
+                mTestSatelliteModemStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        clearInvocations(mMockDatagramController);
+    }
+
+    private void moveSatelliteToDisablingState() {
+        mTestSatelliteSessionController.onSatelliteEnablementStarted(false);
+        processAllMessages();
+
+        // SatelliteSessionController should move to DISABLING state
+        assertSuccessfulModemStateChangedCallback(mTestSatelliteModemStateCallback,
+                SatelliteManager.SATELLITE_MODEM_STATE_DISABLING_SATELLITE);
+        assertEquals(
+                STATE_DISABLING_SATELLITE, mTestSatelliteSessionController.getCurrentStateName());
+    }
+
     private static class TestSatelliteModemInterface extends SatelliteModemInterface {
         private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0);
         private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0);