Merge cherrypicks of ['googleplex-android-review.googlesource.com/30996379', 'googleplex-android-review.googlesource.com/31042170', 'googleplex-android-review.googlesource.com/31035581'] into 25Q1-release.

Change-Id: I5448c3c77cc865c0f49c660137654cb895ec4743
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index 88b9958..fac4358 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -2626,7 +2626,7 @@
         }
 
         @VisibleForTesting
-        public SmsTracker(String destAddr, long messageId) {
+        public SmsTracker(String destAddr, long messageId, String messageText) {
             mData = null;
             mSentIntent = null;
             mDeliveryIntent = null;
@@ -2643,6 +2643,7 @@
             mSkipShortCodeDestAddrCheck = false;
             mUniqueMessageId = 0;
             mResultCodeFromCarrierMessagingService = CarrierMessagingService.SEND_STATUS_OK;
+            mFullMessageText = messageText;
         }
 
         public HashMap<String, Object> getData() {
@@ -2683,6 +2684,22 @@
         }
 
         /**
+         * Check if the message is a MT SMS polling message.
+         *
+         * @param context The Context
+         * @return true if the message is a MT SMS polling message, false otherwise.
+         */
+        public boolean isMtSmsPollingMessage(Context context) {
+            if (mFullMessageText == null) {
+                return false;
+            }
+
+            String mtSmsPollingText =
+                    context.getResources().getString(R.string.config_mt_sms_polling_text);
+            return mFullMessageText.equals(mtSmsPollingText);
+        }
+
+        /**
          * Update the status of this message if we persisted it
          */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index e5afbeb..25a83bd 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -24,6 +24,7 @@
 import android.os.Message;
 import android.telephony.ServiceState;
 
+import com.android.internal.R;
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.InboundSmsHandler;
 import com.android.internal.telephony.Phone;
@@ -165,8 +166,13 @@
                 + " SS=" + ss
                 + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
 
+        boolean allowCheckMessageInNotConnected =
+                mContext.getResources()
+                        .getBoolean(R.bool.config_satellite_allow_check_message_in_not_connected);
+        boolean mtPollingMessageThatsAllowedInOOS =
+                tracker.isMtSmsPollingMessage(mContext) && allowCheckMessageInNotConnected;
         // if sms over IMS is not supported on data and voice is not available...
-        if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
+        if (!isIms() && ss != ServiceState.STATE_IN_SERVICE && !mtPollingMessageThatsAllowedInOOS) {
         //In 5G case only Data Rat is reported.
             if(mPhone.getServiceState().getRilDataRadioTechnology()
                     != ServiceState.RIL_RADIO_TECHNOLOGY_NR) {
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index 5c3bcb0..8c36a2c 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -143,6 +143,8 @@
     private boolean mShouldPollMtSms = false;
     @GuardedBy("mLock")
     private boolean mIsMtSmsPollingThrottled = false;
+    @GuardedBy("mLock")
+    private int mConnectedStateCounter = 0;
 
     /**
      * Create the DatagramDispatcher singleton instance.
@@ -806,6 +808,12 @@
 
             if (state == SATELLITE_MODEM_STATE_CONNECTED) {
                 mHasEnteredConnectedState = true;
+
+                mConnectedStateCounter++;
+                if (isFirstConnected()) {
+                    mShouldPollMtSms = shouldPollMtSms();
+                }
+
                 if (isDatagramWaitForConnectedStateTimerStarted()) {
                     stopDatagramWaitForConnectedStateTimer();
                     sendPendingMessages();
@@ -825,6 +833,11 @@
         }
     }
 
+    /** Returns true if this is the first time the satellite modem is connected. */
+    private boolean isFirstConnected() {
+        return mConnectedStateCounter == 1;
+    }
+
     @GuardedBy("mLock")
     private void cleanUpResources() {
         plogd("cleanUpResources");
@@ -856,6 +869,7 @@
         mModemState = SATELLITE_MODEM_STATE_UNKNOWN;
         mHasEnteredConnectedState = false;
         mShouldPollMtSms = false;
+        mConnectedStateCounter = 0;
         stopMtSmsPollingThrottle();
     }
 
@@ -1254,6 +1268,7 @@
                         getPendingMessagesCount(), SATELLITE_RESULT_SUCCESS);
                 if (datagramType == DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS) {
                     startMtSmsPollingThrottle();
+                    mShouldPollMtSms = false;
                 }
             } else {
                 // Update send status
@@ -1295,7 +1310,9 @@
         }
 
         plogd("sendMtSmsPollingMessage");
-        mShouldPollMtSms = false;
+        if (!allowCheckMessageInNotConnected()) {
+            mShouldPollMtSms = false;
+        }
 
         for (Entry<Long, PendingRequest> entry : mPendingSmsMap.entrySet()) {
             PendingRequest pendingRequest = entry.getValue();
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
index f2f4cac..5cf3c13 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
@@ -875,8 +875,7 @@
 
             //Enable Cellular Modem scanning
             boolean configSatelliteAllowTnScanningDuringSatelliteSession =
-                    mContext.getResources().getBoolean(
-                        R.bool.config_satellite_allow_tn_scanning_during_satellite_session);
+                    isTnScanningAllowedDuringSatelliteSession();
             if (configSatelliteAllowTnScanningDuringSatelliteSession) {
                 Message onCompleted =
                     obtainMessage(EVENT_ENABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE);
@@ -1217,12 +1216,7 @@
                     }
                     break;
                 case EVENT_P2P_SMS_INACTIVITY_TIMER_TIMED_OUT:
-                    if (isEsosInActivityTimerStarted()) {
-                        plogd("NotConnectedState: processing: ESOS inactivity timer running "
-                                + "can not move to IDLE");
-                    } else {
-                        transitionTo(mIdleState);
-                    }
+                    handleEventP2pSmsInactivityTimerTimedOut();
                     break;
                 case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
                     transitionTo(mIdleState);
@@ -1345,12 +1339,7 @@
                     }
                     break;
                 case EVENT_P2P_SMS_INACTIVITY_TIMER_TIMED_OUT:
-                    if (isEsosInActivityTimerStarted()) {
-                        plogd("ConnectedState: processing: ESOS inactivity timer running "
-                                + "can not move to IDLE");
-                    } else {
-                        transitionTo(mIdleState);
-                    }
+                    handleEventP2pSmsInactivityTimerTimedOut();
                     break;
             }
             // Ignore all unexpected events.
@@ -1690,6 +1679,35 @@
         }
     }
 
+    private void handleEventP2pSmsInactivityTimerTimedOut() {
+        if (isEsosInActivityTimerStarted()) {
+            plogd("handleEventP2pSmsInactivityTimerTimedOut: processing: ESOS inactivity timer "
+                    + "running can not move to IDLE");
+        } else {
+            if (isTnScanningAllowedDuringSatelliteSession()) {
+                plogd("handleEventP2pSmsInactivityTimerTimedOut: Transition to IDLE state");
+                transitionTo(mIdleState);
+            } else {
+                if (mSatelliteController.getRequestIsEmergency()) {
+                    plogd("handleEventP2pSmsInactivityTimerTimedOut: Emergency mode");
+                    return;
+                }
+
+                plogd("handleEventP2pSmsInactivityTimerTimedOut: request disable satellite");
+                mSatelliteController.requestSatelliteEnabled(
+                        false /*enableSatellite*/,
+                        false /*enableDemoMode*/,
+                        mSatelliteController.getRequestIsEmergency() /*isEmergency*/,
+                        new IIntegerConsumer.Stub() {
+                            @Override
+                            public void accept(int result) {
+                                plogd("requestSatelliteEnabled result=" + result);
+                            }
+                        });
+            }
+        }
+    }
+
     private int getScreenOffInactivityTimeoutDurationSec() {
         PersistableBundle config = mSatelliteController.getPersistableBundle(getSubId());
 
@@ -1963,6 +1981,16 @@
         }
     }
 
+    private boolean isTnScanningAllowedDuringSatelliteSession() {
+        try {
+            return mContext.getResources().getBoolean(
+                    R.bool.config_satellite_allow_tn_scanning_during_satellite_session);
+        } catch (RuntimeException e) {
+            plogd("isTnScanningAllowedDuringSatelliteSession: ex=" + e);
+            return false;
+        }
+    }
+
     private void plogd(@NonNull String log) {
         logd(log);
         if (mPersistentLogger != null) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java
index b8316cb..15e6ee2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java
@@ -132,7 +132,7 @@
         }
 
         private SMSDispatcher.SmsTracker getSmsTracker(String destAddr, long messageId) {
-            return new SMSDispatcher.SmsTracker(destAddr, messageId);
+            return new SMSDispatcher.SmsTracker(destAddr, messageId, "testMessage");
         }
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
index a29de0f..a31be59 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
@@ -23,6 +23,7 @@
 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
@@ -45,6 +46,7 @@
 import android.content.pm.ServiceInfo;
 import android.location.Country;
 import android.location.CountryDetector;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.Message;
@@ -54,6 +56,7 @@
 import android.service.carrier.CarrierMessagingService;
 import android.service.carrier.ICarrierMessagingCallback;
 import android.service.carrier.ICarrierMessagingService;
+import android.telephony.ServiceState;
 import android.telephony.SmsManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -63,6 +66,7 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.R;
 import com.android.internal.telephony.ContextFixture;
 import com.android.internal.telephony.ISub;
 import com.android.internal.telephony.SMSDispatcher;
@@ -643,4 +647,53 @@
         byte[] pdu = IccUtils.hexStringToBytes(pduCaptor.getValue());
         assertEquals(0, pdu[1]);
     }
+
+    @Test
+    public void testSendRawPdu_isMtSmsPollingMessage_doesNotCallOnFailed() throws Exception {
+        setupMockPackagePermissionChecks();
+        mContextFixture.addCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
+        // return a fake value to pass getData()
+        HashMap data = new HashMap<String, String>();
+        data.put("pdu", new byte[1]);
+        when(mSmsTracker.getData()).thenReturn(data);
+        when(mSmsTracker.getAppPackageName()).thenReturn("");
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 1);
+        // Set isIms() false
+        doReturn(false).when(mSmsDispatchersController).isIms();
+        mContextFixture.putBooleanResource(
+                R.bool.config_satellite_allow_check_message_in_not_connected, true);
+        // Set ServiceState to OOS
+        doReturn(new ServiceState()).when(mPhone).getServiceState();
+        // Set isMtSmsPollingMessage to true
+        when(mSmsTracker.isMtSmsPollingMessage(any())).thenReturn(true);
+
+        mGsmSmsDispatcher.sendRawPdu(new SMSDispatcher.SmsTracker[] {mSmsTracker});
+        processAllMessages();
+
+        verify(mSmsTracker, times(0)).onFailed(any(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void testSmsTracker_isMtSmsPollingMessage_returnsTrue() throws Exception {
+        String mtSmsPollingText = "mt_sms_polling_text";
+        mContextFixture.putResource(R.string.config_mt_sms_polling_text, mtSmsPollingText);
+        SMSDispatcher.SmsTracker tracker =
+                new SMSDispatcher.SmsTracker("destAddr", 0L, mtSmsPollingText);
+
+        boolean isMtSmsPollingMessage = tracker.isMtSmsPollingMessage(mContext);
+
+        assertTrue(isMtSmsPollingMessage);
+    }
+
+    @Test
+    public void testSmsTracker_isMtSmsPollingMessage_returnsFalse() throws Exception {
+        mContextFixture.putResource(R.string.config_mt_sms_polling_text, "mt_sms_polling_text");
+        SMSDispatcher.SmsTracker tracker =
+                new SMSDispatcher.SmsTracker("destAddr", 0L, "wrong_text");
+
+        boolean isMtSmsPollingMessage = tracker.isMtSmsPollingMessage(mContext);
+
+        assertFalse(isMtSmsPollingMessage);
+    }
 }
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 566e5b9..d5fd6f6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -1269,6 +1269,21 @@
         verify(mMockSmsDispatchersController, times(0)).sendMtSmsPollingMessage();
     }
 
+    @Test
+    public void testOnSatelliteModemStateChanged_onFirstConnected_sendsMtSmsPoll() {
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(true);
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+        // Set the following so shouldPollMtSms returns true
+        mContextFixture.putBooleanResource(R.bool.config_enabled_mt_sms_polling, true);
+        when(mMockSatelliteController.shouldSendSmsToDatagramDispatcher(any(Phone.class)))
+                .thenReturn(true);
+
+        mDatagramDispatcherUT.onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+
+        verify(mMockSmsDispatchersController, times(1)).sendMtSmsPollingMessage();
+    }
+
     private void setModemState(int state) {
         mDatagramDispatcherUT.onSatelliteModemStateChanged(state);
     }
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 0d11fed..b5b639e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
@@ -2124,6 +2124,48 @@
         clearInvocations(mMockDatagramController);
     }
 
+    @Test
+    public void testP2pSmsInactivityTimerTimedOut_tnScanningNotSupported() {
+        when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+        when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true);
+
+        when(mMockSatelliteController.getRequestIsEmergency()).thenReturn(false);
+        when(mMockSatelliteController.isSatelliteRoamingP2pSmSSupported(
+                anyInt())).thenReturn(true);
+        when(mMockSatelliteController.getSupportedServicesOnCarrierRoamingNtn(anyInt()))
+                .thenReturn(new int[]{
+                        NetworkRegistrationInfo.SERVICE_TYPE_SMS,
+                        NetworkRegistrationInfo.SERVICE_TYPE_EMERGENCY});
+        when(mMockSatelliteController.isInCarrierRoamingNbIotNtn()).thenReturn(true);
+        Resources resources = mContext.getResources();
+        when(resources.getBoolean(
+                R.bool.config_satellite_allow_tn_scanning_during_satellite_session))
+                .thenReturn(false);
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putInt(KEY_SATELLITE_ROAMING_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);
+        mTestSatelliteSessionController.setSatelliteEnabledForNtnOnlySubscription(false);
+        assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
+        setupDatagramTransferringState(true);
+
+        moveToNotConnectedState();
+
+        // Verify that the P2P SMS inactivity timer is started.
+        assertTrue(mTestSatelliteSessionController.isP2pSmsInActivityTimerStarted());
+
+        // Time shift to cause timeout
+        moveTimeForward(P2P_SMS_INACTIVITY_TIMEOUT_SEC * 1000);
+        processAllMessages();
+
+        // Should disable satellite
+        verify(mMockSatelliteController).requestSatelliteEnabled(
+                eq(false), eq(false), eq(false), any(IIntegerConsumer.Stub.class));
+    }
+
     private void verifyEsosP2pSmsInactivityTimer(boolean esosTimer, boolean p2pSmsTimer) {
         assertEquals(mTestSatelliteSessionController.isEsosInActivityTimerStarted(), esosTimer);
         assertEquals(mTestSatelliteSessionController.isP2pSmsInActivityTimerStarted(),