Add radio state condition for high power indications

Note: Re-merging this CL as a new CL because the automerger
skipped it the first time it was cherry-picked to AOSP.

Bug: 200211834
Test: manual
Original-Change:
https: //android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/1842593
Change-Id: I444a27c436ca3d09225cb681fae419f22c0375d1
(cherry picked from commit b04385df38134abe998c74252f1a016b1c11ec1a)
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index 3967604..368cbf7 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -80,6 +80,8 @@
     @VisibleForTesting
     static final int EVENT_WIFI_CONNECTION_CHANGED      = 7;
     static final int EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH = 8;
+    static final int EVENT_RADIO_ON                     = 9;
+    static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE   = 10;
 
     private static final int WIFI_UNAVAILABLE = 0;
     private static final int WIFI_AVAILABLE = 1;
@@ -178,6 +180,12 @@
     private boolean mIsAutomotiveProjectionActive;
 
     /**
+     * Radio is on. False means that radio is either off or not available and it is ok to reduce
+     * commands to the radio to avoid unnecessary power consumption.
+     */
+    private boolean mIsRadioOn;
+
+    /**
      * True indicates we should always enable the signal strength reporting from radio.
      */
     private boolean mIsAlwaysSignalStrengthReportingEnabled;
@@ -269,6 +277,7 @@
         mIsPowerSaveOn = isPowerSaveModeOn();
         mIsCharging = isDeviceCharging();
         mIsScreenOn = isScreenOn();
+        mIsRadioOn = isRadioOn();
         mIsAutomotiveProjectionActive = isAutomotiveProjectionActive();
         // Assuming tethering is always off after boot up.
         mIsTetheringOn = false;
@@ -282,7 +291,8 @@
                 + ", mIsAutomotiveProjectionActive=" + mIsAutomotiveProjectionActive
                 + ", mIsWifiConnected=" + mIsWifiConnected
                 + ", mIsAlwaysSignalStrengthReportingEnabled="
-                + mIsAlwaysSignalStrengthReportingEnabled, false);
+                + mIsAlwaysSignalStrengthReportingEnabled
+                + ", mIsRadioOn=" + mIsRadioOn, false);
 
         final IntentFilter filter = new IntentFilter();
         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
@@ -293,6 +303,8 @@
 
         mPhone.mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
         mPhone.mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+        mPhone.mCi.registerForOn(this, EVENT_RADIO_ON, null);
+        mPhone.mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
 
         ConnectivityManager cm = (ConnectivityManager) phone.getContext().getSystemService(
                 Context.CONNECTIVITY_SERVICE);
@@ -313,7 +325,7 @@
      * @return True if low data is expected
      */
     private boolean isLowDataExpected() {
-        return !mIsCharging && !mIsTetheringOn && !mIsScreenOn;
+        return (!mIsCharging && !mIsTetheringOn && !mIsScreenOn) || !mIsRadioOn;
     }
 
     /**
@@ -397,12 +409,14 @@
      * @return True if the response update should be enabled.
      */
     public boolean shouldEnableHighPowerConsumptionIndications() {
-        // We should enable indications reports if one of the following condition is true.
+        // We should enable indications reports if radio is on and one of the following conditions
+        // is true:
         // 1. The device is charging.
         // 2. When the screen is on.
         // 3. When the tethering is on.
         // 4. When automotive projection (Android Auto) is on.
-        return mIsCharging || mIsScreenOn || mIsTetheringOn || mIsAutomotiveProjectionActive;
+        return (mIsCharging || mIsScreenOn || mIsTetheringOn || mIsAutomotiveProjectionActive)
+                && mIsRadioOn;
     }
 
     /**
@@ -453,6 +467,12 @@
             case EVENT_RADIO_AVAILABLE:
                 onReset();
                 break;
+            case EVENT_RADIO_ON:
+                onUpdateDeviceState(msg.what, /* state= */ true);
+                break;
+            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
+                onUpdateDeviceState(msg.what, /* state= */ false);
+                break;
             case EVENT_SCREEN_STATE_CHANGED:
             case EVENT_POWER_SAVE_MODE_CHANGED:
             case EVENT_CHARGING_STATE_CHANGED:
@@ -488,6 +508,11 @@
                 mIsCharging = state;
                 sendDeviceState(CHARGING_STATE, mIsCharging);
                 break;
+            case EVENT_RADIO_ON:
+            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
+                if (mIsRadioOn == state) return;
+                mIsRadioOn = state;
+                break;
             case EVENT_TETHERING_STATE_CHANGED:
                 if (mIsTetheringOn == state) return;
                 mIsTetheringOn = state;
@@ -707,6 +732,13 @@
     }
 
     /**
+     * @return True if the radio is on.
+     */
+    private boolean isRadioOn() {
+        return mPhone.isRadioOn();
+    }
+
+    /**
      * @return True if automotive projection (Android Auto) is active.
      */
     private boolean isAutomotiveProjectionActive() {
@@ -772,6 +804,7 @@
         ipw.println("mIsWifiConnected=" + mIsWifiConnected);
         ipw.println("mIsAlwaysSignalStrengthReportingEnabled="
                 + mIsAlwaysSignalStrengthReportingEnabled);
+        ipw.println("mIsRadioOn=" + mIsRadioOn);
         ipw.println("Local logs:");
         ipw.increaseIndent();
         mLocalLog.dump(fd, ipw, args);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index aa52e71..6f442fe 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -96,7 +96,6 @@
     // Keep the same value as corresponding event
     // See state2Event() for detail
     private static final int STATE_TYPE_RIL_CONNECTED = 0;
-    // EVENT_UPDATE_NODE_CHANGED is not here, it will be removed in aosp soon
     private static final int STATE_TYPE_SCREEN = 2;
     private static final int STATE_TYPE_POWER_SAVE_MODE = 3;
     private static final int STATE_TYPE_CHARGING = 4;
@@ -104,6 +103,8 @@
     private static final int STATE_TYPE_RADIO_AVAILABLE = 6;
     private static final int STATE_TYPE_WIFI_CONNECTED = 7;
     private static final int STATE_TYPE_ALWAYS_SIGNAL_STRENGTH_REPORTED = 8;
+    private static final int STATE_TYPE_RADIO_ON = 9;
+    private static final int STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE = 10;
 
     /** @hide */
     @IntDef(prefix = {"STATE_"}, value = {
@@ -236,20 +237,43 @@
     public void testScreenOnOff() {
         // screen was off by default, turn it on now
         updateState(STATE_TYPE_SCREEN, STATE_ON);
-        processAllMessages();
 
         verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                 eq(INDICATION_FILTERS_WHEN_SCREEN_ON), nullable(Message.class));
 
         // turn screen off
         updateState(STATE_TYPE_SCREEN, STATE_OFF);
-        processAllMessages();
 
         verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                 eq(INDICATION_FILTERS_MINIMUM), nullable(Message.class));
     }
 
     @Test
+    public void testScreenOnOffwithRadioToggle() {
+        // screen was off by default, turn it on now
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+        // turn off radio
+        updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, /* stateValue is not used */ 0);
+
+        verify(mSimulatedCommandsVerifier)
+                .sendDeviceState(eq(LOW_DATA_EXPECTED), eq(true), nullable(Message.class));
+        reset(mSimulatedCommandsVerifier);
+
+        // turn screen off and on
+        updateState(STATE_TYPE_SCREEN, STATE_OFF);
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+
+        verify(mSimulatedCommandsVerifier, never())
+                .sendDeviceState(anyInt(), anyBoolean(), nullable(Message.class));
+
+        // turn on radio
+        updateState(STATE_TYPE_RADIO_ON, /* stateValue is not used */ 0);
+
+        verify(mSimulatedCommandsVerifier)
+                .sendDeviceState(eq(LOW_DATA_EXPECTED), eq(false), nullable(Message.class));
+    }
+
+    @Test
     public void testTethering() {
         // Turn tethering on
         Intent intent = new Intent(TetheringManager.ACTION_TETHER_STATE_CHANGED);
@@ -376,4 +400,29 @@
         updateState(STATE_TYPE_SCREEN, STATE_ON);
         verify(mSimulatedCommandsVerifier).getBarringInfo(nullable(Message.class));
     }
+
+    @Test
+    public void testGetBarringInfowithRadioToggle() {
+        // screen was off by default, turn it on now
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+
+        verify(mSimulatedCommandsVerifier).getBarringInfo(nullable(Message.class));
+        reset(mSimulatedCommandsVerifier);
+
+        // turn off radio
+        updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, /* stateValue is not used */ 0);
+
+        verify(mSimulatedCommandsVerifier, never()).getBarringInfo(nullable(Message.class));
+
+        // turn screen off and on
+        updateState(STATE_TYPE_SCREEN, STATE_OFF);
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+
+        verify(mSimulatedCommandsVerifier, never()).getBarringInfo(nullable(Message.class));
+
+        // turn on radio
+        updateState(STATE_TYPE_RADIO_ON, /* stateValue is not used */ 0);
+
+        verify(mSimulatedCommandsVerifier).getBarringInfo(nullable(Message.class));
+    }
 }