Merge "Fix that changes in desiredHdrSdrRatio doesn't update brightness" into main
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index c04c279..39172b8 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -25,6 +25,7 @@
 import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.MathUtils;
@@ -33,6 +34,7 @@
 import android.view.SurfaceControlHdrLayerInfoListener;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.display.BrightnessSynchronizer;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
 import com.android.server.display.DisplayManagerService.Clock;
@@ -99,6 +101,7 @@
     private boolean mIsHdrLayerPresent = false;
     // mMaxDesiredHdrSdrRatio should only be applied when there is a valid backlight->nits mapping
     private float mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+    private boolean mForceHbmChangeCallback = false;
     private boolean mIsBlockedByLowPowerMode = false;
     private int mWidth;
     private int mHeight;
@@ -484,7 +487,8 @@
     private void updateHbmMode() {
         int newHbmMode = calculateHighBrightnessMode();
         updateHbmStats(newHbmMode);
-        if (mHbmMode != newHbmMode) {
+        if (mHbmMode != newHbmMode || mForceHbmChangeCallback) {
+            mForceHbmChangeCallback = false;
             mHbmMode = newHbmMode;
             mHbmChangeCallback.run();
         }
@@ -600,26 +604,32 @@
         public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
                 int maxW, int maxH, int flags, float maxDesiredHdrSdrRatio) {
             mHandler.post(() -> {
+                Trace.traceBegin(Trace.TRACE_TAG_POWER, "HBMController#onHdrInfoChanged");
                 mIsHdrLayerPresent = numberOfHdrLayers > 0
                         && (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
                                    * mHbmData.minimumHdrPercentOfScreen);
 
-                final float candidateDesiredHdrSdrRatio =
+                float candidateDesiredHdrSdrRatio =
                         mIsHdrLayerPresent && mHdrBrightnessCfg != null
                                 ? maxDesiredHdrSdrRatio
                                 : DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
 
-                if (candidateDesiredHdrSdrRatio >= 1.0f) {
-                    mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
-                } else {
+                if (candidateDesiredHdrSdrRatio < 1.0f) {
                     Slog.w(TAG, "Ignoring invalid desired HDR/SDR Ratio: "
                             + candidateDesiredHdrSdrRatio);
-                    mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+                    candidateDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+                }
+
+                if (!BrightnessSynchronizer.floatEquals(
+                        mMaxDesiredHdrSdrRatio, candidateDesiredHdrSdrRatio)) {
+                    mForceHbmChangeCallback = true;
+                    mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
                 }
 
                 // Calling the brightness update so that we can recalculate
                 // brightness with HDR in mind.
                 onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
+                Trace.traceEnd(Trace.TRACE_TAG_POWER);
             });
         }
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 76e6ec7..8e01a11 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -32,8 +32,10 @@
 import static org.mockito.Mockito.anyFloat;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -390,6 +392,35 @@
         assertEquals(Float.POSITIVE_INFINITY, hbmc.getHdrBrightnessValue(), 0.0);
     }
 
+    @Test
+    public void testHdrRespectsChangingDesiredHdrSdrRatio() {
+        final Runnable hbmChangedCallback = mock(Runnable.class);
+        final HighBrightnessModeController hbmc = new TestHbmBuilder()
+                .setClock(new OffsettableClock())
+                .setHdrBrightnessConfig(mHdrBrightnessDeviceConfigMock)
+                .setHbmChangedCallback(hbmChangedCallback)
+                .build();
+
+        // Passthrough return the max desired hdr/sdr ratio
+        when(mHdrBrightnessDeviceConfigMock.getHdrBrightnessFromSdr(anyFloat(), anyFloat()))
+                .thenAnswer(i -> i.getArgument(1));
+
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 2.0f /*maxDesiredHdrSdrRatio*/);
+        advanceTime(0);
+        assertEquals(2.0f, hbmc.getHdrBrightnessValue(), EPSILON);
+        verify(hbmChangedCallback, times(1)).run();
+
+        // Verify that a change in only the desired hdrSdrRatio still results in the changed
+        // callback being invoked
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/,
+                3.0f /*maxDesiredHdrSdrRatio*/);
+        advanceTime(0);
+        assertEquals(3.0f, hbmc.getHdrBrightnessValue(), 0.0);
+        verify(hbmChangedCallback, times(2)).run();
+    }
+
 
     @Test
     public void testHdrTrumpsSunlight() {
@@ -698,6 +729,7 @@
     private class TestHbmBuilder {
         OffsettableClock mClock;
         HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessCfg;
+        Runnable mHdrChangedCallback = () -> {};
 
         TestHbmBuilder setClock(OffsettableClock clock) {
             mClock = clock;
@@ -711,6 +743,11 @@
             return this;
         }
 
+        TestHbmBuilder setHbmChangedCallback(Runnable runnable) {
+            mHdrChangedCallback = runnable;
+            return this;
+        }
+
         HighBrightnessModeController build() {
             initHandler(mClock);
             if (mHighBrightnessModeMetadata == null) {
@@ -718,8 +755,8 @@
             }
             return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
                     DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
-                    DEFAULT_HBM_DATA, mHdrBrightnessCfg, () -> {}, mHighBrightnessModeMetadata,
-                    mContextSpy);
+                    DEFAULT_HBM_DATA, mHdrBrightnessCfg, mHdrChangedCallback,
+                    mHighBrightnessModeMetadata, mContextSpy);
         }
 
     }