Push keepAlive datagram to modem in NOT_CONNECTED state

Bug: 335522718
Test: SatelliteManagerTestOnMockService DatagramControllerTest
DatagramDispatcherTest DatagramReceiverTest
Manual test with Skylo demo and real mode

Change-Id: I8c0e521f24efd7f6ec78e2081094d15f37e152a9
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java
index d4e97db..6300640 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramController.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java
@@ -17,11 +17,13 @@
 package com.android.internal.telephony.satellite;
 
 import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE;
 import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_IDLE;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
@@ -241,6 +243,10 @@
                     + " datagramType: " + datagramType
                     + " datagramTransferState: " + datagramTransferState
                     + " sendPendingCount: " + sendPendingCount + " errorCode: " + errorCode);
+            if (shouldSuppressDatagramTransferStateUpdate(datagramType)) {
+                logd("Ignore the request to update send status");
+                return;
+            }
 
             mSendSubId = subId;
             mDatagramType = datagramType;
@@ -254,6 +260,20 @@
         }
     }
 
+    private boolean shouldSuppressDatagramTransferStateUpdate(
+            @SatelliteManager.DatagramType int datagramType) {
+        synchronized (mLock) {
+            if (!SatelliteController.getInstance().isSatelliteAttachRequired()) {
+                return false;
+            }
+            if (datagramType == DATAGRAM_TYPE_KEEP_ALIVE
+                    && mSatelltieModemState == SATELLITE_MODEM_STATE_NOT_CONNECTED) {
+                return true;
+            }
+            return false;
+        }
+    }
+
     /**
      * Update receive status to {@link PointingAppController}.
      *
@@ -334,10 +354,17 @@
      * before transferring datagrams via satellite.
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public boolean needsWaitingForSatelliteConnected() {
+    public boolean needsWaitingForSatelliteConnected(
+            @SatelliteManager.DatagramType int datagramType) {
         synchronized (mLock) {
-            if (SatelliteController.getInstance().isSatelliteAttachRequired()
-                    && mSatelltieModemState != SATELLITE_MODEM_STATE_CONNECTED
+            if (!SatelliteController.getInstance().isSatelliteAttachRequired()) {
+                return false;
+            }
+            if (datagramType == DATAGRAM_TYPE_KEEP_ALIVE
+                    && mSatelltieModemState == SATELLITE_MODEM_STATE_NOT_CONNECTED) {
+                return false;
+            }
+            if (mSatelltieModemState != SATELLITE_MODEM_STATE_CONNECTED
                     && mSatelltieModemState != SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING) {
                 return true;
             }
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index f8ebbd6..6f7b23a 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -379,7 +379,7 @@
                 mPendingNonEmergencyDatagramsMap.put(datagramId, datagramArgs);
             }
 
-            if (mDatagramController.needsWaitingForSatelliteConnected()) {
+            if (mDatagramController.needsWaitingForSatelliteConnected(datagramType)) {
                 logd("sendDatagram: wait for satellite connected");
                 mDatagramController.updateSendStatus(subId, datagramType,
                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
@@ -513,9 +513,14 @@
         }
 
         if ((pendingDatagram != null) && pendingDatagram.iterator().hasNext()) {
-            mSendingDatagramInProgress = true;
             SendSatelliteDatagramArgument datagramArg =
                     pendingDatagram.iterator().next().getValue();
+            if (mDatagramController.needsWaitingForSatelliteConnected(datagramArg.datagramType)) {
+                logd("sendPendingDatagrams: wait for satellite connected");
+                return;
+            }
+
+            mSendingDatagramInProgress = true;
             // Sets the trigger time for getting pending datagrams
             datagramArg.setDatagramStartTime();
             mDatagramController.updateSendStatus(datagramArg.subId, datagramArg.datagramType,
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index 4f54833..145b017 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -594,7 +594,8 @@
             return;
         }
 
-        if (mDatagramController.needsWaitingForSatelliteConnected()) {
+        if (mDatagramController.needsWaitingForSatelliteConnected(
+                SatelliteManager.DATAGRAM_TYPE_UNKNOWN)) {
             logd("pollPendingSatelliteDatagramsInternal: wait for satellite connected");
             synchronized (mLock) {
                 mPendingPollSatelliteDatagramsRequest = new DatagramReceiverHandlerRequest(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
index 78322ff..9c9a677 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
@@ -31,10 +31,14 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.os.Looper;
 import android.telephony.satellite.SatelliteDatagram;
+import android.telephony.satellite.SatelliteManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -60,6 +64,7 @@
     @Mock private DatagramDispatcher mMockDatagramDispatcher;
     @Mock private PointingAppController mMockPointingAppController;
     @Mock private SatelliteSessionController mMockSatelliteSessionController;
+    @Mock private SatelliteController mMockSatelliteController;
 
     private static final int SUB_ID = 0;
 
@@ -73,9 +78,12 @@
                 mMockDatagramDispatcher);
         replaceInstance(DatagramReceiver.class, "sInstance", null,
                 mMockDatagramReceiver);
+        replaceInstance(SatelliteController.class, "sInstance", null,
+                mMockSatelliteController);
         replaceInstance(SatelliteSessionController.class, "sInstance", null,
                 mMockSatelliteSessionController);
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);
         mDatagramControllerUT = new DatagramController(
                 mContext, Looper.myLooper(), mMockPointingAppController);
 
@@ -116,6 +124,55 @@
         testSetDeviceAlignedWithSatellite(false);
     }
 
+    @Test
+    public void testSuppressSendStatusUpdate() throws Exception {
+        // Move to NOT_CONNECTED state
+        mDatagramControllerUT.onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
+
+        clearInvocations(mMockSatelliteSessionController);
+        clearInvocations(mMockPointingAppController);
+        clearInvocations(mMockDatagramReceiver);
+
+        int sendPendingCount = 1;
+        int errorCode = SATELLITE_RESULT_SUCCESS;
+        mDatagramControllerUT.updateSendStatus(SUB_ID, DATAGRAM_TYPE_KEEP_ALIVE,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, sendPendingCount, errorCode);
+        verifyZeroInteractions(mMockSatelliteSessionController);
+        verifyZeroInteractions(mMockPointingAppController);
+        verifyZeroInteractions(mMockDatagramReceiver);
+    }
+
+    @Test
+    public void testNeedsWaitingForSatelliteConnected() throws Exception {
+        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(false);
+        assertFalse(mDatagramControllerUT
+                .needsWaitingForSatelliteConnected(DATAGRAM_TYPE_KEEP_ALIVE));
+
+        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);
+        mDatagramControllerUT.onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
+        assertFalse(mDatagramControllerUT
+                .needsWaitingForSatelliteConnected(DATAGRAM_TYPE_KEEP_ALIVE));
+        assertTrue(mDatagramControllerUT
+                .needsWaitingForSatelliteConnected(DATAGRAM_TYPE_SOS_MESSAGE));
+
+        mDatagramControllerUT.onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        assertFalse(mDatagramControllerUT
+                .needsWaitingForSatelliteConnected(DATAGRAM_TYPE_SOS_MESSAGE));
+
+        mDatagramControllerUT.onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
+        assertFalse(mDatagramControllerUT
+                .needsWaitingForSatelliteConnected(DATAGRAM_TYPE_SOS_MESSAGE));
+
+        mDatagramControllerUT.onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
+        assertTrue(mDatagramControllerUT
+                .needsWaitingForSatelliteConnected(DATAGRAM_TYPE_SOS_MESSAGE));
+    }
+
     private void testUpdateSendStatus(boolean isDemoMode, int datagramType, int sendState) {
         mDatagramControllerUT.setDemoMode(isDemoMode);
         clearAllInvocations();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
index 3708a47..6f8d080 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -176,7 +176,7 @@
         }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
                 anyBoolean(), anyBoolean(), any(Message.class));
         doReturn(true).when(mMockDatagramController)
-                .needsWaitingForSatelliteConnected();
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         when(mMockDatagramController.getDatagramWaitTimeForConnectedState())
                 .thenReturn(TEST_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT_MILLIS);
         mResultListener.clear();
@@ -184,7 +184,8 @@
         mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
         processAllMessages();
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mInOrder.verify(mMockDatagramController).updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                 eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(1),
                 eq(SATELLITE_RESULT_SUCCESS));
@@ -192,12 +193,16 @@
         verifyZeroInteractions(mMockSatelliteModemInterface);
         assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
 
+        doReturn(false).when(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mDatagramDispatcherUT.onSatelliteModemStateChanged(
                 SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
+        mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
                         eq(SATELLITE_RESULT_SUCCESS));
@@ -224,11 +229,14 @@
         clearInvocations(mMockSatelliteModemInterface);
         clearInvocations(mMockDatagramController);
         mResultListener.clear();
+        doReturn(true).when(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
         processAllMessages();
         verifyZeroInteractions(mMockSatelliteModemInterface);
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState();
         assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
 
@@ -265,7 +273,8 @@
                 true, mResultListener::offer);
         processAllMessages();
         verifyZeroInteractions(mMockSatelliteModemInterface);
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState();
         assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
         assertEquals(0, mResultListener.size());
@@ -299,7 +308,7 @@
         }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
                 anyBoolean(), anyBoolean(), any(Message.class));
         doReturn(false).when(mMockDatagramController)
-                .needsWaitingForSatelliteConnected();
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         when(mMockDatagramController.getDatagramWaitTimeForConnectedState())
                 .thenReturn(TEST_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT_MILLIS);
         mContextFixture.putIntResource(
@@ -310,7 +319,8 @@
         mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
         processAllMessages();
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
@@ -340,7 +350,8 @@
         mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
         processAllMessages();
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
@@ -381,7 +392,8 @@
 
         processAllMessages();
 
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE2));
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
@@ -534,7 +546,8 @@
                 true, mResultListener::offer);
         processAllMessages();
         // As modem is busy receiving datagrams, sending datagram did not proceed further.
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(DATAGRAM_TYPE1));
         mInOrder.verify(mMockDatagramController, times(2)).isPollingInIdleState();
         verifyNoMoreInteractions(mMockDatagramController);
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
index 7eae18b..361c638 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -138,7 +138,8 @@
 
         when(mMockDatagramController.isSendingInIdleState()).thenReturn(true);
         when(mMockDatagramController.isPollingInIdleState()).thenReturn(true);
-        when(mMockDatagramController.needsWaitingForSatelliteConnected()).thenReturn(false);
+        when(mMockDatagramController.needsWaitingForSatelliteConnected(
+                eq(SatelliteManager.DATAGRAM_TYPE_UNKNOWN))).thenReturn(false);
         processAllMessages();
     }
 
@@ -167,14 +168,16 @@
                     .sendToTarget();
             return null;
         }).when(mMockSatelliteModemInterface).pollPendingSatelliteDatagrams(any(Message.class));
-        doReturn(true).when(mMockDatagramController).needsWaitingForSatelliteConnected();
+        doReturn(true).when(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(SatelliteManager.DATAGRAM_TYPE_UNKNOWN));
         when(mMockDatagramController.getDatagramWaitTimeForConnectedState())
                 .thenReturn(TEST_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT_MILLIS);
         mResultListener.clear();
 
         mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
         processAllMessages();
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(SatelliteManager.DATAGRAM_TYPE_UNKNOWN));
         mInOrder.verify(mMockDatagramController).updateReceiveStatus(eq(SUB_ID),
                 eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(0),
                 eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
@@ -182,7 +185,8 @@
         verifyZeroInteractions(mMockSatelliteModemInterface);
         assertTrue(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted());
 
-        doReturn(false).when(mMockDatagramController).needsWaitingForSatelliteConnected();
+        doReturn(false).when(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(SatelliteManager.DATAGRAM_TYPE_UNKNOWN));
         mDatagramReceiverUT.onSatelliteModemStateChanged(
                 SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         processAllMessages();
@@ -200,10 +204,12 @@
         clearInvocations(mMockSatelliteModemInterface);
         clearInvocations(mMockSessionMetricsStats);
         mResultListener.clear();
-        doReturn(true).when(mMockDatagramController).needsWaitingForSatelliteConnected();
+        doReturn(true).when(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(SatelliteManager.DATAGRAM_TYPE_UNKNOWN));
         mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
         processAllMessages();
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController)
+                .needsWaitingForSatelliteConnected(eq(SatelliteManager.DATAGRAM_TYPE_UNKNOWN));
         mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState();
         verifyZeroInteractions(mMockSatelliteModemInterface);
         assertTrue(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted());