Merge "Add new apis for satellite service" into main
diff --git a/flags/ims.aconfig b/flags/ims.aconfig
index 84e491e..b41ef4d 100644
--- a/flags/ims.aconfig
+++ b/flags/ims.aconfig
@@ -1 +1,8 @@
-package: "com.android.internal.telephony.flags"
\ No newline at end of file
+package: "com.android.internal.telephony.flags"
+
+flag {
+    name: "conference_hold_unhold_changed_to_send_message"
+    namespace: "telephony"
+    description: "This flag controls Conference’s hold & unHold operation changed to send a message"
+    bug:"288002989"
+}
\ No newline at end of file
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 5205616..722cb7c 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -381,6 +381,7 @@
     optional bool is_internet_pdn_up = 11;
     optional int32 fold_state = 12;
     optional bool override_voice_service = 13;
+    optional bool isDataEnabled = 14;
 
     // Internal use only
     optional int64 last_used_millis = 10001;
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java
index 73874e8..d1c8359 100644
--- a/src/java/com/android/internal/telephony/NetworkTypeController.java
+++ b/src/java/com/android/internal/telephony/NetworkTypeController.java
@@ -165,6 +165,7 @@
     private int mLtePlusThresholdBandwidth;
     private int mNrAdvancedThresholdBandwidth;
     private boolean mIncludeLteForNrAdvancedThresholdBandwidth;
+    private boolean mRatchetPccFieldsForSameAnchorNrCell;
     @NonNull private final Set<Integer> mAdditionalNrAdvancedBands = new HashSet<>();
     @NonNull private String mPrimaryTimerState;
     @NonNull private String mSecondaryTimerState;
@@ -300,6 +301,8 @@
                 CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT);
         mIncludeLteForNrAdvancedThresholdBandwidth = config.getBoolean(
                 CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL);
+        mRatchetPccFieldsForSameAnchorNrCell = config.getBoolean(
+                CarrierConfigManager.KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL);
         mEnableNrAdvancedWhileRoaming = config.getBoolean(
                 CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL);
         mAdditionalNrAdvancedBands.clear();
@@ -565,9 +568,9 @@
                     quit();
                     break;
                 case EVENT_INITIALIZE:
-                    // The reason that we do it here is because some of the works below requires
-                    // other modules (e.g. DataNetworkController, ServiceStateTracker), which is not
-                    // created yet when NetworkTypeController is created.
+                    // The reason that we do it here is that the work below requires other modules
+                    // (e.g. DataNetworkController, ServiceStateTracker), which are not created
+                    // when NetworkTypeController is created.
                     registerForAllEvents();
                     parseCarrierConfigs();
                     break;
@@ -1056,6 +1059,13 @@
     private void updatePhysicalChannelConfigs() {
         List<PhysicalChannelConfig> physicalChannelConfigs =
                 mPhone.getServiceStateTracker().getPhysicalChannelConfigList();
+        boolean isPccListEmpty = physicalChannelConfigs == null || physicalChannelConfigs.isEmpty();
+        if (isPccListEmpty && isUsingPhysicalChannelConfigForRrcDetection()) {
+            log("Physical channel configs updated: not updating PCC fields for empty PCC list "
+                    + "indicating RRC idle.");
+            mPhysicalChannelConfigs = physicalChannelConfigs;
+            return;
+        }
 
         int anchorNrCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN;
         int anchorLteCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN;
@@ -1088,33 +1098,24 @@
             anchorNrCellId = anchorLteCellId;
         }
 
-        boolean wasLastAnchorNrCellIdValid =
-                mLastAnchorNrCellId != PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN;
-        if ((physicalChannelConfigs == null || physicalChannelConfigs.isEmpty())
-                && wasLastAnchorNrCellIdValid && isUsingPhysicalChannelConfigForRrcDetection()) {
-            log("Keep same anchor NR cell and PCC fields for empty PCC list indicating RRC idle.");
-            // Set to mLastAnchorNrCellId since it will be UNKNOWN if the PCC list is empty
-            anchorNrCellId = mLastAnchorNrCellId;
-        }
-        if (mLastAnchorNrCellId == anchorNrCellId && wasLastAnchorNrCellIdValid) {
+        if (anchorNrCellId == PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN) {
+            if (!isPccListEmpty) {
+                log("Ignoring physical channel config fields without an anchor NR cell, "
+                        + "either due to LTE-only configs or an unspecified cell ID.");
+            }
+            mRatchetedNrBandwidths = 0;
+            mRatchetedNrBands.clear();
+        } else if (anchorNrCellId == mLastAnchorNrCellId && mRatchetPccFieldsForSameAnchorNrCell) {
             log("Ratchet physical channel config fields since anchor NR cell is the same.");
             mRatchetedNrBandwidths = Math.max(mRatchetedNrBandwidths, nrBandwidths);
             mRatchetedNrBands.addAll(nrBands);
         } else {
-            if (anchorNrCellId == PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN) {
-                if (wasLastAnchorNrCellIdValid) {
-                    // Only log when the previous anchor NR cell was valid to prevent log spam
-                    log("Clearing physical channel config fields without an anchor NR cell, "
-                            + "either due to LTE-only configs or an unspecified cell ID.");
-                }
-                mRatchetedNrBandwidths = 0;
-                mRatchetedNrBands.clear();
-            } else {
-                log("Not ratcheting physical channel config fields since anchor NR cell changed "
+            if (mRatchetPccFieldsForSameAnchorNrCell) {
+                log("Not ratcheting physical channel config fields since anchor NR cell changed: "
                         + mLastAnchorNrCellId + " -> " + anchorNrCellId);
-                mRatchetedNrBandwidths = nrBandwidths;
-                mRatchetedNrBands = nrBands;
             }
+            mRatchetedNrBandwidths = nrBandwidths;
+            mRatchetedNrBands = nrBands;
         }
 
         mLastAnchorNrCellId = anchorNrCellId;
@@ -1351,7 +1352,7 @@
         // Check PCO requirement. For carriers using PCO to indicate whether the data connection is
         // NR advanced capable, mNrAdvancedCapablePcoId should be configured to non-zero.
         if (mNrAdvancedCapablePcoId > 0 && !mIsNrAdvancedAllowedByPco) {
-            if (DBG) log("isNrAdvanced: false because PCO ID " + mNrAdvancedCapablePcoId + " <= 0");
+            if (DBG) log("isNrAdvanced: not allowed by PCO for PCO ID " + mNrAdvancedCapablePcoId);
             return false;
         }
 
@@ -1460,6 +1461,9 @@
                 + mIsTimerResetEnabledForLegacyStateRrcIdle);
         pw.println("mLtePlusThresholdBandwidth=" + mLtePlusThresholdBandwidth);
         pw.println("mNrAdvancedThresholdBandwidth=" + mNrAdvancedThresholdBandwidth);
+        pw.println("mIncludeLteForNrAdvancedThresholdBandwidth="
+                + mIncludeLteForNrAdvancedThresholdBandwidth);
+        pw.println("mRatchetPccFieldsForSameAnchorNrCell=" + mRatchetPccFieldsForSameAnchorNrCell);
         pw.println("mRatchetedNrBandwidths=" + mRatchetedNrBandwidths);
         pw.println("mAdditionalNrAdvancedBandsList=" + mAdditionalNrAdvancedBands);
         pw.println("mRatchetedNrBands=" + mRatchetedNrBands);
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 94e2c5c..c56c544 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -686,7 +686,7 @@
         // system setting property AIRPLANE_MODE_ON is set in Settings.
         int airplaneMode = Settings.Global.getInt(mCr, Settings.Global.AIRPLANE_MODE_ON, 0);
         int enableCellularOnBoot = Settings.Global.getInt(mCr,
-                Settings.Global.ENABLE_CELLULAR_ON_BOOT, getDefaultEnableCellularOnBoot());
+                Settings.Global.ENABLE_CELLULAR_ON_BOOT, 1);
         mDesiredPowerState = (enableCellularOnBoot > 0) && ! (airplaneMode > 0);
         if (!mDesiredPowerState) {
             mRadioPowerOffReasons.add(TelephonyManager.RADIO_POWER_REASON_USER);
@@ -750,11 +750,6 @@
         }
     }
 
-    private int getDefaultEnableCellularOnBoot() {
-        return mPhone.getContext().getResources().getBoolean(
-            R.bool.config_enable_cellular_on_boot_default) ? 1 : 0;
-    }
-
     @VisibleForTesting
     public void updatePhoneType() {
 
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index a04a63a..1a53ee6 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -933,7 +933,8 @@
                 state.isEmergencyOnly,
                 state.isInternetPdnUp,
                 state.foldState,
-                state.overrideVoiceService);
+                state.overrideVoiceService,
+                state.isDataEnabled);
     }
 
     private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index c3312e1..d495ca2 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -1710,7 +1710,8 @@
                     && state.isEmergencyOnly == key.isEmergencyOnly
                     && state.isInternetPdnUp == key.isInternetPdnUp
                     && state.foldState == key.foldState
-                    && state.overrideVoiceService == key.overrideVoiceService) {
+                    && state.overrideVoiceService == key.overrideVoiceService
+                    && state.isDataEnabled == key.isDataEnabled) {
                 return state;
             }
         }
diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
index 982a8f5..14ce2cc 100644
--- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
@@ -131,6 +131,7 @@
             newState.isInternetPdnUp = isInternetPdnUp(mPhone);
             newState.foldState = mDeviceStateHelper.getFoldState();
             newState.overrideVoiceService = mOverrideVoiceService.get();
+            newState.isDataEnabled = mPhone.getDataSettingsManager().isDataEnabled();
             TimestampedServiceState prevState =
                     mLastState.getAndSet(new TimestampedServiceState(newState, now));
             addServiceStateAndSwitch(
@@ -300,6 +301,7 @@
         copy.isInternetPdnUp = state.isInternetPdnUp;
         copy.foldState = state.foldState;
         copy.overrideVoiceService = state.overrideVoiceService;
+        copy.isDataEnabled = state.isDataEnabled;
         return copy;
     }
 
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java
index d790ca9..32acdcf 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramController.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java
@@ -315,16 +315,14 @@
     public boolean isSendingInIdleState() {
         synchronized (mLock) {
             return (mSendDatagramTransferState
-                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE)
-                    && (mDatagramDispatcher.getPendingDatagramCount() == 0);
+                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         }
     }
 
     public boolean isPollingInIdleState() {
         synchronized (mLock) {
             return (mReceiveDatagramTransferState
-                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE)
-                    && !mDatagramReceiver.isPollingPending();
+                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index b8d9ef4..591114b 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -359,7 +359,9 @@
 
             if (mDatagramController.needsWaitingForSatelliteConnected()) {
                 logd("sendSatelliteDatagram: wait for satellite connected");
-                SatelliteSessionController.getInstance().onSatelliteDatagramsTransferRequested();
+                mDatagramController.updateSendStatus(subId,
+                        SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
+                        getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
                 startDatagramWaitForConnectedStateTimer();
             } else if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) {
                 // Modem can be busy receiving datagrams, so send datagram only when modem is
@@ -645,9 +647,16 @@
     private void handleEventDatagramWaitForConnectedStateTimedOut() {
         logw("Timed out to wait for satellite connected before sending datagrams");
         synchronized (mLock) {
+            // Update send status
+            mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
+                    getPendingDatagramCount(),
+                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+            mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
+                    0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
             abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                     SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
-            SatelliteSessionController.getInstance().onDatagramWaitForConnectedStateTimerTimedOut();
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index cd98f43..35c78eb 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -602,16 +602,6 @@
         pollPendingSatelliteDatagramsInternal(subId, callback);
     }
 
-    /**
-     * Check if DatagramReceiver is waiting for satellite modem connected to a satellite network
-     * before pushing down the poll request to modem.
-     */
-    public boolean isPollingPending() {
-        synchronized (mLock) {
-            return (mPendingPollSatelliteDatagramsRequest != null);
-        }
-    }
-
     private void handleSatelliteConnectedEvent() {
         synchronized (mLock) {
             if (isDatagramWaitForConnectedStateTimerStarted()) {
@@ -645,7 +635,10 @@
             synchronized (mLock) {
                 mPendingPollSatelliteDatagramsRequest = new DatagramReceiverHandlerRequest(
                         callback, SatelliteServiceUtils.getPhone(), subId);
-                SatelliteSessionController.getInstance().onSatelliteDatagramsTransferRequested();
+                mDatagramController.updateReceiveStatus(subId,
+                        SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
+                        mDatagramController.getReceivePendingCount(),
+                        SatelliteManager.SATELLITE_RESULT_SUCCESS);
                 startDatagramWaitForConnectedStateTimer();
             }
             return;
@@ -874,11 +867,24 @@
             }
 
             logw("Timed out to wait for satellite connected before polling datagrams");
+            mDatagramController.updateReceiveStatus(mPendingPollSatelliteDatagramsRequest.subId,
+                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED,
+                    mDatagramController.getReceivePendingCount(),
+                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+
+            mDatagramController.updateReceiveStatus(mPendingPollSatelliteDatagramsRequest.subId,
+                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
+                    mDatagramController.getReceivePendingCount(),
+                    SatelliteManager.SATELLITE_RESULT_SUCCESS);
+
+            reportMetrics(null, SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+            mControllerMetricsStats.reportIncomingDatagramCount(
+                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+
             Consumer<Integer> callback =
                     (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument;
             callback.accept(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
             mPendingPollSatelliteDatagramsRequest = null;
-            SatelliteSessionController.getInstance().onDatagramWaitForConnectedStateTimerTimedOut();
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 050dfbc..01ba435 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -2514,7 +2514,6 @@
                 loge("handleEventSatelliteModemStateChanged: mSatelliteSessionController is null");
             }
         }
-        mDatagramController.onSatelliteModemStateChanged(state);
     }
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
index d84ceeb..d0497eb 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS;
@@ -23,6 +24,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -97,10 +99,8 @@
     private static final int EVENT_LISTENING_TIMER_TIMEOUT = 2;
     private static final int EVENT_SATELLITE_ENABLED_STATE_CHANGED = 3;
     private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 4;
-    private static final int EVENT_SATELLITE_DATAGRAMS_TRANSFER_REQUESTED = 5;
-    private static final int EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE = 6;
-    protected static final int EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT = 7;
-    private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMER_TIMED_OUT = 8;
+    private static final int EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE = 5;
+    protected static final int EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT = 6;
 
     private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds
     private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute
@@ -137,6 +137,7 @@
     @GuardedBy("mLock")
     @NonNull private boolean mIsDisableCellularModemInProgress = false;
     @NonNull private final SatelliteController mSatelliteController;
+    @NonNull private final DatagramController mDatagramController;
 
     /**
      * @return The singleton instance of SatelliteSessionController.
@@ -188,6 +189,7 @@
         mContext = context;
         mSatelliteModemInterface = satelliteModemInterface;
         mSatelliteController = SatelliteController.getInstance();
+        mDatagramController = DatagramController.getInstance();
         mSatelliteStayAtListeningFromSendingMillis = getSatelliteStayAtListeningFromSendingMillis();
         mSatelliteStayAtListeningFromReceivingMillis =
                 getSatelliteStayAtListeningFromReceivingMillis();
@@ -255,26 +257,6 @@
     }
 
     /**
-     * {@link DatagramDispatcher} and {@link DatagramReceiver} use this function to notify
-     * {@link SatelliteSessionController} that it has received a request to send satellite
-     * datagrams or poll pending satellite datagrams.
-     */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public void onSatelliteDatagramsTransferRequested() {
-        sendMessage(EVENT_SATELLITE_DATAGRAMS_TRANSFER_REQUESTED);
-    }
-
-    /**
-     * {@link DatagramDispatcher} and {@link DatagramReceiver} use this function to notify
-     * {@link SatelliteSessionController} that the datagram wait for connected state timer has
-     * timed out.
-     */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public void onDatagramWaitForConnectedStateTimerTimedOut() {
-        sendMessage(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMER_TIMED_OUT);
-    }
-
-    /**
      * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController}
      * that the satellite modem state has changed.
      *
@@ -407,6 +389,7 @@
         public void enter() {
             if (DBG) logd("Entering UnavailableState");
             mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE;
+            notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE);
         }
 
         @Override
@@ -483,9 +466,6 @@
                 case EVENT_SATELLITE_ENABLED_STATE_CHANGED:
                     handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "IdleState");
                     break;
-                case EVENT_SATELLITE_DATAGRAMS_TRANSFER_REQUESTED:
-                    disableCellularModemWhileSatelliteModeIsOn();
-                    break;
                 case EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE:
                     handleEventDisableCellularModemWhileSatelliteModeIsOnDone(
                             (AsyncResult) msg.obj);
@@ -505,6 +485,15 @@
                 } else {
                     transitionTo(mTransferringState);
                 }
+            } else if ((datagramTransferState.sendState
+                    == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT)
+                    || (datagramTransferState.receiveState
+                    == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT)) {
+                if (mSatelliteController.isSatelliteAttachRequired()) {
+                    disableCellularModemWhileSatelliteModeIsOn();
+                } else {
+                    loge("Unexpected transferring state received for non-NB-IOT NTN");
+                }
             }
         }
 
@@ -694,11 +683,8 @@
                 case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
                     transitionTo(mIdleState);
                     break;
-                case EVENT_SATELLITE_DATAGRAMS_TRANSFER_REQUESTED:
-                    stopNbIotInactivityTimer();
-                    break;
-                case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMER_TIMED_OUT:
-                    startNbIotInactivityTimer();
+                case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED:
+                    handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj);
                     break;
             }
             // Ignore all unexpected events.
@@ -711,6 +697,20 @@
                 transitionTo(mConnectedState);
             }
         }
+
+        private void handleEventDatagramTransferStateChanged(
+                @NonNull DatagramTransferState datagramTransferState) {
+            if (datagramTransferState.sendState
+                    == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT
+                    || datagramTransferState.receiveState
+                    == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT) {
+                stopNbIotInactivityTimer();
+            } else if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE
+                    && datagramTransferState.receiveState
+                    == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
+                startNbIotInactivityTimer();
+            }
+        }
     }
 
     private class ConnectedState extends State {
@@ -786,18 +786,12 @@
             case EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE:
                 whatString = "EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE";
                 break;
-            case EVENT_SATELLITE_DATAGRAMS_TRANSFER_REQUESTED:
-                whatString = "EVENT_SATELLITE_DATAGRAMS_TRANSFER_REQUESTED";
-                break;
             case EVENT_SATELLITE_MODEM_STATE_CHANGED:
                 whatString = "EVENT_SATELLITE_MODEM_STATE_CHANGED";
                 break;
             case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT:
                 whatString = "EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT";
                 break;
-            case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMER_TIMED_OUT:
-                whatString = "EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMER_TIMED_OUT";
-                break;
             default:
                 whatString = "UNKNOWN EVENT " + what;
         }
@@ -813,6 +807,8 @@
     }
 
     private void notifyStateChangedEvent(@SatelliteManager.SatelliteModemState int state) {
+        mDatagramController.onSatelliteModemStateChanged(state);
+
         List<ISatelliteStateCallback> toBeRemoved = new ArrayList<>();
         mListeners.values().forEach(listener -> {
             try {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
index fbf169c..7f15af8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
@@ -571,6 +571,8 @@
         mBundle.putIntArray(CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY,
                 new int[]{41, 77});
         mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
+        mBundle.putBoolean(CarrierConfigManager.KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL,
+                true);
         sendCarrierConfigChanged();
 
         // Primary serving NR PCC with cell ID = 1, band = none, bandwidth = 200000
@@ -632,6 +634,101 @@
     }
 
     @Test
+    public void testEventPhysicalChannelConfigChangedWithoutRatcheting() throws Exception {
+        testTransitionToCurrentStateNrConnected();
+        mBundle.putIntArray(CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY,
+                new int[]{41, 77});
+        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
+        sendCarrierConfigChanged();
+
+        // Primary serving NR PCC with cell ID = 1, band = none, bandwidth = 200000
+        PhysicalChannelConfig pcc1 = new PhysicalChannelConfig.Builder()
+                .setNetworkType(TelephonyManager.NETWORK_TYPE_NR)
+                .setPhysicalCellId(1)
+                .setCellConnectionStatus(CellInfo.CONNECTION_PRIMARY_SERVING)
+                .setCellBandwidthDownlinkKhz(19999)
+                .build();
+        // Secondary serving NR PCC with cell ID = 2, band = 41, bandwidth = 10000
+        PhysicalChannelConfig pcc2 = new PhysicalChannelConfig.Builder()
+                .setNetworkType(TelephonyManager.NETWORK_TYPE_NR)
+                .setPhysicalCellId(2)
+                .setCellConnectionStatus(CellInfo.CONNECTION_SECONDARY_SERVING)
+                .setCellBandwidthDownlinkKhz(10000)
+                .setBand(41)
+                .build();
+
+        List<PhysicalChannelConfig> physicalChannelConfigs = new ArrayList<>();
+        physicalChannelConfigs.add(pcc1);
+        physicalChannelConfigs.add(pcc2);
+        doReturn(physicalChannelConfigs).when(mSST).getPhysicalChannelConfigList();
+
+        mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */);
+        processAllMessages();
+        assertEquals("connected_mmwave", getCurrentState().getName());
+
+        // bands and bandwidths should stay ratcheted even if an empty PCC list is sent
+        doReturn(new ArrayList<>()).when(mSST).getPhysicalChannelConfigList();
+        mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */);
+        processAllMessages();
+        assertEquals("connected_mmwave", getCurrentState().getName());
+
+        // bands and bandwidths should change if PCC list changes
+        physicalChannelConfigs.remove(pcc2);
+        doReturn(physicalChannelConfigs).when(mSST).getPhysicalChannelConfigList();
+        mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */);
+        processAllMessages();
+        assertEquals("connected", getCurrentState().getName());
+    }
+
+    @Test
+    public void testEventPhysicalChannelConfigChangedUsingUserDataForRrc() throws Exception {
+        testTransitionToCurrentStateNrConnected();
+        mBundle.putIntArray(CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY,
+                new int[]{41, 77});
+        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
+        mBundle.putBoolean(CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL,
+                true);
+        sendCarrierConfigChanged();
+
+        // Primary serving NR PCC with cell ID = 1, band = none, bandwidth = 200000
+        PhysicalChannelConfig pcc1 = new PhysicalChannelConfig.Builder()
+                .setNetworkType(TelephonyManager.NETWORK_TYPE_NR)
+                .setPhysicalCellId(1)
+                .setCellConnectionStatus(CellInfo.CONNECTION_PRIMARY_SERVING)
+                .setCellBandwidthDownlinkKhz(19999)
+                .build();
+        // Secondary serving NR PCC with cell ID = 2, band = 41, bandwidth = 10000
+        PhysicalChannelConfig pcc2 = new PhysicalChannelConfig.Builder()
+                .setNetworkType(TelephonyManager.NETWORK_TYPE_NR)
+                .setPhysicalCellId(2)
+                .setCellConnectionStatus(CellInfo.CONNECTION_SECONDARY_SERVING)
+                .setCellBandwidthDownlinkKhz(10000)
+                .setBand(41)
+                .build();
+
+        List<PhysicalChannelConfig> physicalChannelConfigs = new ArrayList<>();
+        physicalChannelConfigs.add(pcc1);
+        physicalChannelConfigs.add(pcc2);
+        doReturn(physicalChannelConfigs).when(mSST).getPhysicalChannelConfigList();
+
+        mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */);
+        processAllMessages();
+        assertEquals("connected_mmwave", getCurrentState().getName());
+
+        // bands and bandwidths should not stay the same even if an empty PCC list is sent
+        doReturn(new ArrayList<>()).when(mSST).getPhysicalChannelConfigList();
+        mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */);
+        processAllMessages();
+        assertEquals("connected", getCurrentState().getName());
+
+        // bands and bandwidths should change if PCC list changes
+        doReturn(physicalChannelConfigs).when(mSST).getPhysicalChannelConfigList();
+        mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */);
+        processAllMessages();
+        assertEquals("connected_mmwave", getCurrentState().getName());
+    }
+
+    @Test
     public void testNrPhysicalChannelChangeFromNrConnectedMmwaveToLteConnected() throws Exception {
         testTransitionToCurrentStateNrConnectedMmwave();
         doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
index 5d7eb9c..2509b8c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
@@ -158,6 +158,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -330,6 +331,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -342,6 +344,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -379,6 +382,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat);
@@ -391,6 +395,7 @@
         assertEquals(200L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -425,6 +430,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -466,6 +472,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -504,6 +511,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = serviceStateCaptor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -516,6 +524,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0);
         assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, serviceSwitch.ratFrom);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratTo);
@@ -557,6 +566,7 @@
         assertEquals(CARRIER1_ID, state.carrierId);
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -568,6 +578,7 @@
         assertEquals(CARRIER1_ID, state.carrierId);
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -597,6 +608,7 @@
         assertEquals(0L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -638,6 +650,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -650,6 +663,7 @@
         assertEquals(200L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(2);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -662,6 +676,7 @@
         assertEquals(400L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(3);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -674,6 +689,7 @@
         assertEquals(800L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -719,6 +735,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat);
@@ -731,6 +748,7 @@
         assertEquals(5000L, state.totalTimeMillis);
         assertEquals(true, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(2);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -743,6 +761,7 @@
         assertEquals(200L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -808,6 +827,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = serviceStateCaptor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat);
@@ -820,6 +840,7 @@
         assertEquals(200L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = serviceStateCaptor.getAllValues().get(2);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat);
@@ -832,6 +853,7 @@
         assertEquals(400L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratFrom);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, serviceSwitch.ratTo);
@@ -888,6 +910,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = serviceStateCaptor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat);
@@ -901,6 +924,7 @@
         assertEquals(400L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratFrom);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, serviceSwitch.ratTo);
@@ -957,6 +981,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = serviceStateCaptor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -969,6 +994,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = serviceStateCaptor.getAllValues().get(2);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat);
@@ -981,6 +1007,7 @@
         assertEquals(200L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = serviceStateCaptor.getAllValues().get(3);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat);
@@ -993,6 +1020,7 @@
         assertEquals(200L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratFrom);
         assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, serviceSwitch.ratTo);
@@ -1054,6 +1082,7 @@
         assertEquals(100L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         state = captor.getAllValues().get(1);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat);
@@ -1066,6 +1095,7 @@
         assertEquals(200L, state.totalTimeMillis);
         assertEquals(false, state.isEmergencyOnly);
         assertEquals(true, state.isInternetPdnUp);
+        assertEquals(true, state.isDataEnabled);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -1320,6 +1350,7 @@
         doReturn(1).when(mSecondPhone).getPhoneId();
         doReturn(1).when(mUiccController).getSlotIdFromPhoneId(1);
         doReturn(carrierId).when(mSecondPhone).getCarrierId();
+        doReturn(mDataSettingsManager).when(mSecondPhone).getDataSettingsManager();
 
         doReturn(true).when(mPhysicalSlot1).isActive();
         doReturn(CardState.CARDSTATE_PRESENT).when(mPhysicalSlot1).getCardState();
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 c5f1c45..e80978d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -42,6 +42,7 @@
 import android.os.AsyncResult;
 import android.os.Looper;
 import android.os.Message;
+import android.telephony.SubscriptionManager;
 import android.telephony.satellite.SatelliteDatagram;
 import android.telephony.satellite.SatelliteManager;
 import android.testing.AndroidTestingRunner;
@@ -149,8 +150,10 @@
                 true, mResultListener::offer);
         processAllMessages();
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController).updateSendStatus(eq(SUB_ID),
+                eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(1),
+                eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState();
-        verify(mMockSatelliteSessionController).onSatelliteDatagramsTransferRequested();
         verifyZeroInteractions(mMockSatelliteModemInterface);
         assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
 
@@ -196,7 +199,14 @@
         moveTimeForward(DatagramController.DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT);
         processAllMessages();
         verifyZeroInteractions(mMockSatelliteModemInterface);
-        verifyZeroInteractions(mMockDatagramController);
+        mInOrder.verify(mMockDatagramController)
+                .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(1),
+                        eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE));
+        mInOrder.verify(mMockDatagramController)
+                .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
+                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
         assertEquals(1, mResultListener.size());
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
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 18f89db..9fe85ef 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -168,6 +168,9 @@
         mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
         processAllMessages();
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
+        mInOrder.verify(mMockDatagramController).updateReceiveStatus(eq(SUB_ID),
+                eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(0),
+                eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState();
         verifyZeroInteractions(mMockSatelliteModemInterface);
         assertTrue(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted());
@@ -199,6 +202,12 @@
 
         moveTimeForward(DatagramController.DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT);
         processAllMessages();
+        mInOrder.verify(mMockDatagramController).updateReceiveStatus(eq(SUB_ID),
+                eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), eq(0),
+                eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE));
+        mInOrder.verify(mMockDatagramController).updateReceiveStatus(eq(SUB_ID),
+                eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
+                eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
         verifyZeroInteractions(mMockSatelliteModemInterface);
         assertEquals(1, mResultListener.size());
         assertThat(mResultListener.peek()).isEqualTo(
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 888b014..50c6c24 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java
@@ -21,12 +21,15 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
@@ -420,6 +423,9 @@
                 mTestSatelliteStateCallback, 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);
 
         moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS);
         processAllMessages();
@@ -437,6 +443,9 @@
         assertSuccessfulModemStateChangedCallback(
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF);
         assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_OFF);
+        clearInvocations(mMockDatagramController);
 
         // Power on the modem.
         mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true);
@@ -447,6 +456,9 @@
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
         assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
         assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Start sending datagrams
         mTestSatelliteSessionController.onDatagramTransferStateChanged(
@@ -467,6 +479,9 @@
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
         assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Start sending datagrams
         mTestSatelliteSessionController.onDatagramTransferStateChanged(
@@ -478,6 +493,9 @@
                 SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
         assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName());
         assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
+        clearInvocations(mMockDatagramController);
 
         // Sending datagrams failed
         mTestSatelliteSessionController.onDatagramTransferStateChanged(
@@ -490,6 +508,9 @@
                 SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
         assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Start sending datagrams again
         mTestSatelliteSessionController.onDatagramTransferStateChanged(
@@ -502,6 +523,9 @@
                 SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
         assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName());
         assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
+        clearInvocations(mMockDatagramController);
 
         // Sending datagrams is successful and done.
         mTestSatelliteSessionController.onDatagramTransferStateChanged(
@@ -514,6 +538,9 @@
                 SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
         assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Start receiving datagrams
         mTestSatelliteSessionController.onDatagramTransferStateChanged(
@@ -526,6 +553,9 @@
                 SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
         assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName());
         assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING);
+        clearInvocations(mMockDatagramController);
 
         // Receiving datagrams is successful and done.
         mTestSatelliteSessionController.onDatagramTransferStateChanged(
@@ -537,6 +567,9 @@
                 SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
         assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Wait for timeout
         moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS);
@@ -547,15 +580,23 @@
                 SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
         assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName());
         assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_IDLE);
+        clearInvocations(mMockDatagramController);
 
         // Start sending datagrams
-        mTestSatelliteSessionController.onSatelliteDatagramsTransferRequested();
+        mTestSatelliteSessionController.onDatagramTransferStateChanged(
+                SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         processAllMessages();
 
         // SatelliteSessionController should move to NOT_CONNECTED state.
         assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback,
                 SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
         assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Satellite modem is connected to a satellite network.
         mTestSatelliteSessionController.onSatelliteModemStateChanged(
@@ -566,6 +607,9 @@
         assertSuccessfulModemStateChangedCallback(
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Satellite modem is disconnected from the satellite network.
         mTestSatelliteSessionController.onSatelliteModemStateChanged(
@@ -576,6 +620,9 @@
         assertSuccessfulModemStateChangedCallback(
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
         assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Satellite modem is connected to a satellite network.
         mTestSatelliteSessionController.onSatelliteModemStateChanged(
@@ -586,6 +633,9 @@
         assertSuccessfulModemStateChangedCallback(
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
         assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Power off the modem.
         mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false);
@@ -595,6 +645,9 @@
         assertSuccessfulModemStateChangedCallback(
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF);
         assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_OFF);
+        clearInvocations(mMockDatagramController);
 
         // Power on the modem.
         mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true);
@@ -605,6 +658,9 @@
         assertSuccessfulModemStateChangedCallback(
                 mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
         assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
+        verify(mMockDatagramController).onSatelliteModemStateChanged(
+                SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED);
+        clearInvocations(mMockDatagramController);
 
         // Satellite modem is connected to a satellite network.
         mTestSatelliteSessionController.onSatelliteModemStateChanged(
@@ -629,7 +685,9 @@
         mSatelliteModemInterface.setErrorCode(SatelliteManager.SATELLITE_RESULT_MODEM_ERROR);
 
         // Start sending datagrams
-        mTestSatelliteSessionController.onSatelliteDatagramsTransferRequested();
+        mTestSatelliteSessionController.onDatagramTransferStateChanged(
+                SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         processAllMessages();
 
         // SatelliteSessionController should stay at IDLE state because it failed to disable
@@ -687,7 +745,9 @@
         assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName());
 
         // Start sending datagrams and the NB-IOT inactivity timer should be stopped.
-        mTestSatelliteSessionController.onSatelliteDatagramsTransferRequested();
+        mTestSatelliteSessionController.onDatagramTransferStateChanged(
+                SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS);
         processAllMessages();
 
@@ -697,7 +757,12 @@
 
         // Transferring datagram failed because satellite failed to connect to a satellite network.
         // The NB-IOT inactivity timer should be started.
-        mTestSatelliteSessionController.onDatagramWaitForConnectedStateTimerTimedOut();
+        mTestSatelliteSessionController.onDatagramTransferStateChanged(
+                SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+        mTestSatelliteSessionController.onDatagramTransferStateChanged(
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         processAllMessages();
         assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted());