DisplayPowerController uses max desired SDR/HDR ratio

When an application requests a smaller max designed SDR/HDR ratio than
what is supported by the system, DisplayPowerController should clamp to
the smallest ratio bigger than 1.0.

Bug: 267350616
Test: SilkFX test app
Change-Id: I933ca05c1f336ee2102489bbc850d42bcf612c4c
diff --git a/core/java/android/view/SurfaceControlHdrLayerInfoListener.java b/core/java/android/view/SurfaceControlHdrLayerInfoListener.java
index 13d68d0..b79fd2d 100644
--- a/core/java/android/view/SurfaceControlHdrLayerInfoListener.java
+++ b/core/java/android/view/SurfaceControlHdrLayerInfoListener.java
@@ -42,10 +42,13 @@
      * @param maxH The height of the HDR layer with the largest area
      * @param flags Additional metadata flags, currently always 0
      *              TODO(b/182312559): Add some flags
+     * @param maxDesiredHdrSdrRatio The max desired HDR/SDR ratio. Unbounded if the ratio is
+     *                              positive infinity.
      *
-     * @hide */
+     * @hide
+     */
     public abstract void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
-            int maxW, int maxH, int flags);
+            int maxW, int maxH, int flags, float maxDesiredHdrSdrRatio);
 
     /**
      * Registers this as an HDR info listener on the provided display
diff --git a/core/jni/android_view_SurfaceControlHdrLayerInfoListener.cpp b/core/jni/android_view_SurfaceControlHdrLayerInfoListener.cpp
index adbd791..443f99a 100644
--- a/core/jni/android_view_SurfaceControlHdrLayerInfoListener.cpp
+++ b/core/jni/android_view_SurfaceControlHdrLayerInfoListener.cpp
@@ -42,12 +42,12 @@
         LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mVm) != JNI_OK, "Failed to GetJavaVm");
     }
 
-    binder::Status onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH,
-                                         int flags) override {
+    binder::Status onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH, int flags,
+                                         float maxDesiredHdrSdrRatio) override {
         JNIEnv* env = requireEnv();
 
         env->CallVoidMethod(mListener, gListenerClassInfo.mOnHdrInfoChanged, mDisplayToken,
-                            numberOfHdrLayers, maxW, maxH, flags);
+                            numberOfHdrLayers, maxW, maxH, flags, maxDesiredHdrSdrRatio);
 
         if (env->ExceptionCheck()) {
             ALOGE("SurfaceControlHdrLayerInfoListener.onHdrInfoChanged() failed.");
@@ -129,7 +129,7 @@
     jclass clazz = env->FindClass("android/view/SurfaceControlHdrLayerInfoListener");
     gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
     gListenerClassInfo.mOnHdrInfoChanged =
-            env->GetMethodID(clazz, "onHdrInfoChanged", "(Landroid/os/IBinder;IIII)V");
+            env->GetMethodID(clazz, "onHdrInfoChanged", "(Landroid/os/IBinder;IIIIF)V");
     return 0;
 }
 
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index d9b3501..33af227 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -851,11 +851,12 @@
     }
 
     /**
-     * Calculate the HDR brightness for the specified SDR brightenss.
+     * Calculate the HDR brightness for the specified SDR brightenss, restricted by the
+     * maxDesiredHdrSdrRatio (the ratio between the HDR luminance and SDR luminance)
      *
      * @return the HDR brightness or BRIGHTNESS_INVALID when no mapping exists.
      */
-    public float getHdrBrightnessFromSdr(float brightness) {
+    public float getHdrBrightnessFromSdr(float brightness, float maxDesiredHdrSdrRatio) {
         if (mSdrToHdrRatioSpline == null) {
             return PowerManager.BRIGHTNESS_INVALID;
         }
@@ -866,7 +867,7 @@
             return PowerManager.BRIGHTNESS_INVALID;
         }
 
-        float ratio = mSdrToHdrRatioSpline.interpolate(nits);
+        float ratio = Math.min(mSdrToHdrRatioSpline.interpolate(nits), maxDesiredHdrSdrRatio);
         float hdrNits = nits * ratio;
         if (mNitsToBacklightSpline == null) {
             return PowerManager.BRIGHTNESS_INVALID;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 82e6e30..2535941 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -966,8 +966,10 @@
                 mDisplayDeviceConfig.getHighBrightnessModeData(),
                 new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
                     @Override
-                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
-                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+                    public float getHdrBrightnessFromSdr(
+                            float sdrBrightness, float maxDesiredHdrSdrRatio) {
+                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+                                sdrBrightness, maxDesiredHdrSdrRatio);
                     }
                 });
         mBrightnessThrottler.resetThrottlingData(
@@ -2069,8 +2071,10 @@
                 displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
                 new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
                     @Override
-                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
-                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+                    public float getHdrBrightnessFromSdr(
+                            float sdrBrightness, float maxDesiredHdrSdrRatio) {
+                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+                                sdrBrightness, maxDesiredHdrSdrRatio);
                     }
                 },
                 () -> {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 0861a37..da70432 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -804,8 +804,10 @@
                 mDisplayDeviceConfig.getHighBrightnessModeData(),
                 new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
                     @Override
-                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
-                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+                    public float getHdrBrightnessFromSdr(
+                            float sdrBrightness, float maxDesiredHdrSdrRatio) {
+                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+                                sdrBrightness, maxDesiredHdrSdrRatio);
                     }
                 });
         mBrightnessThrottler.resetThrottlingData(
@@ -1776,8 +1778,10 @@
                 displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
                 new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
                     @Override
-                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
-                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+                    public float getHdrBrightnessFromSdr(
+                            float sdrBrightness, float maxDesiredHdrSdrRatio) {
+                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+                                sdrBrightness, maxDesiredHdrSdrRatio);
                     }
                 },
                 () -> {
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 2c843a4..ca208ac 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -61,8 +61,12 @@
     @VisibleForTesting
     static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;
 
+    private static final float DEFAULT_MAX_DESIRED_HDR_SDR_RATIO = 1.0f;
+
     public interface HdrBrightnessDeviceConfig {
-        float getHdrBrightnessFromSdr(float sdrBrightness);
+        // maxDesiredHdrSdrRatio will restrict the HDR brightness if the ratio is less than
+        // Float.POSITIVE_INFINITY
+        float getHdrBrightnessFromSdr(float sdrBrightness, float maxDesiredHdrSdrRatio);
     }
 
     private final float mBrightnessMin;
@@ -96,6 +100,9 @@
 
     private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
     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 mIsThermalStatusWithinLimit = true;
     private boolean mIsBlockedByLowPowerMode = false;
     private int mWidth;
@@ -177,7 +184,8 @@
 
     float getHdrBrightnessValue() {
         if (mHdrBrightnessCfg != null) {
-            float hdrBrightness = mHdrBrightnessCfg.getHdrBrightnessFromSdr(mBrightness);
+            float hdrBrightness = mHdrBrightnessCfg.getHdrBrightnessFromSdr(
+                    mBrightness, mMaxDesiredHdrSdrRatio);
             if (hdrBrightness != PowerManager.BRIGHTNESS_INVALID) {
                 return hdrBrightness;
             }
@@ -457,6 +465,7 @@
                     + ", isLuxHigh: " + mIsInAllowedAmbientRange
                     + ", isHBMCurrentlyAllowed: " + isCurrentlyAllowed()
                     + ", isHdrLayerPresent: " + mIsHdrLayerPresent
+                    + ", mMaxDesiredHdrSdrRatio: " + mMaxDesiredHdrSdrRatio
                     + ", isAutoBrightnessEnabled: " +  mIsAutoBrightnessEnabled
                     + ", mIsTimeAvailable: " + mIsTimeAvailable
                     + ", mIsInAllowedAmbientRange: " + mIsInAllowedAmbientRange
@@ -600,11 +609,25 @@
     class HdrListener extends SurfaceControlHdrLayerInfoListener {
         @Override
         public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
-                int maxW, int maxH, int flags) {
+                int maxW, int maxH, int flags, float maxDesiredHdrSdrRatio) {
             mHandler.post(() -> {
                 mIsHdrLayerPresent = numberOfHdrLayers > 0
                         && (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
                                    * mHbmData.minimumHdrPercentOfScreen);
+
+                final float candidateDesiredHdrSdrRatio =
+                        mIsHdrLayerPresent && mHdrBrightnessCfg != null
+                                ? maxDesiredHdrSdrRatio
+                                : DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+
+                if (candidateDesiredHdrSdrRatio >= 1.0f) {
+                    mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
+                } else {
+                    Slog.w(TAG, "Ignoring invalid desired HDR/SDR Ratio: "
+                            + candidateDesiredHdrSdrRatio);
+                    mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+                }
+
                 // Calling the brightness update so that we can recalculate
                 // brightness with HDR in mind.
                 onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index fdfcd81..17cf017 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -230,6 +230,18 @@
         assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
         assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMinorVersion(), 0);
 
+        // Max desired Hdr/SDR ratio upper-bounds the HDR brightness.
+        assertEquals(1.0f,
+                mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, Float.POSITIVE_INFINITY),
+                ZERO_DELTA);
+        assertEquals(0.62f,
+                mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.0f),
+                ZERO_DELTA);
+        assertEquals(0.77787f,
+                mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.25f),
+                SMALL_DELTA);
+
+
         // Todo: Add asserts for BrightnessThrottlingData, DensityMapping,
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
     }
@@ -361,6 +373,16 @@
                 +       "</refreshRate>\n"
                 +       "<thermalStatusLimit>light</thermalStatusLimit>\n"
                 +       "<allowInLowPowerMode>false</allowInLowPowerMode>\n"
+                +       "<sdrHdrRatioMap>\n"
+                +            "<point>\n"
+                +                "<sdrNits>2.000</sdrNits>\n"
+                +                "<hdrRatio>4.000</hdrRatio>\n"
+                +            "</point>\n"
+                +            "<point>\n"
+                +                "<sdrNits>500.0</sdrNits>\n"
+                +                "<hdrRatio>1.6</hdrRatio>\n"
+                +            "</point>\n"
+                +       "</sdrHdrRatioMap>\n"
                 +   "</highBrightnessMode>\n"
                 +   "<screenOffBrightnessSensor>\n"
                 +       "<type>sensor_12345</type>\n"
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 2655c3f..3b10db4 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -29,6 +29,7 @@
 import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.anyFloat;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
@@ -103,6 +104,7 @@
 
     @Mock IThermalService mThermalServiceMock;
     @Mock Injector mInjectorMock;
+    @Mock HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessDeviceConfigMock;
 
     @Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor;
 
@@ -376,18 +378,49 @@
 
         // ensure hdr doesn't turn on if layer is too small
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                layerWidth, smallLayerHeight, 0 /*flags*/);
+                layerWidth, smallLayerHeight, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
 
         // Now check with layer larger than 50%
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                layerWidth, largeLayerHeight, 0 /*flags*/);
+                layerWidth, largeLayerHeight, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
     }
 
     @Test
+    public void testHdrRespectsMaxDesiredHdrSdrRatio() {
+        final HighBrightnessModeController hbmc = new TestHbmBuilder()
+                .setClock(new OffsettableClock())
+                .setHdrBrightnessConfig(mHdrBrightnessDeviceConfigMock)
+                .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);
+
+        // The hdr ratio cannot be less than 1.
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 0.5f /*maxDesiredHdrSdrRatio*/);
+        advanceTime(0);
+        assertEquals(1.0f, hbmc.getHdrBrightnessValue(), EPSILON);
+
+        // The hdr ratio can be as much as positive infinity
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/,
+                Float.POSITIVE_INFINITY /*maxDesiredHdrSdrRatio*/);
+        advanceTime(0);
+        assertEquals(Float.POSITIVE_INFINITY, hbmc.getHdrBrightnessValue(), 0.0);
+    }
+
+
+    @Test
     public void testHdrTrumpsSunlight() {
         final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
 
@@ -400,7 +433,7 @@
 
         // turn on hdr
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
         assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
@@ -412,14 +445,14 @@
 
         // Check limit when HBM is off
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
         assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
 
         // Check limit with HBM is set to HDR
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 0 /*numberOfHdrLayers*/,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
         assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
@@ -430,7 +463,7 @@
         final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
 
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
 
@@ -473,7 +506,7 @@
         hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
         hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT);
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
 
@@ -483,7 +516,7 @@
             eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
 
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 0 /*numberOfHdrLayers*/,
-                0, 0, 0 /*flags*/);
+                0, 0, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
 
         // Verify Stats HBM_OFF
@@ -517,7 +550,7 @@
         hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
         hbmcOnBrightnessChanged(hbmc, DEFAULT_MIN);
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
         assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
 
@@ -657,7 +690,7 @@
             eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
 
         hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
-                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
         advanceTime(0);
 
         verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
@@ -696,19 +729,42 @@
         assertEquals(hbmMode, hbmc.getHighBrightnessMode());
     }
 
+    private class TestHbmBuilder {
+        OffsettableClock mClock;
+        HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessCfg;
+
+        TestHbmBuilder setClock(OffsettableClock clock) {
+            mClock = clock;
+            return this;
+        }
+
+        TestHbmBuilder setHdrBrightnessConfig(
+                HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg
+        ) {
+            mHdrBrightnessCfg = hdrBrightnessCfg;
+            return this;
+        }
+
+        HighBrightnessModeController build() {
+            initHandler(mClock);
+            if (mHighBrightnessModeMetadata == null) {
+                mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
+            }
+            return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
+                    DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
+                    DEFAULT_HBM_DATA, mHdrBrightnessCfg, () -> {}, mHighBrightnessModeMetadata,
+                    mContextSpy);
+        }
+
+    }
+
     private HighBrightnessModeController createDefaultHbm() {
-        return createDefaultHbm(null);
+        return new TestHbmBuilder().build();
     }
 
     // Creates instance with standard initialization values.
     private HighBrightnessModeController createDefaultHbm(OffsettableClock clock) {
-        initHandler(clock);
-        if (mHighBrightnessModeMetadata == null) {
-            mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
-        }
-        return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
-                DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
-                DEFAULT_HBM_DATA, null, () -> {}, mHighBrightnessModeMetadata, mContextSpy);
+        return new TestHbmBuilder().setClock(clock).build();
     }
 
     private void initHandler(OffsettableClock clock) {