Loading core/java/android/hardware/display/BrightnessInfo.java +2 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,8 @@ public final class BrightnessInfo implements Parcelable { @IntDef(prefix = {"BRIGHTNESS_MAX_REASON_"}, value = { BRIGHTNESS_MAX_REASON_NONE, BRIGHTNESS_MAX_REASON_THERMAL, BRIGHTNESS_MAX_REASON_POWER_IC BRIGHTNESS_MAX_REASON_POWER_IC, BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE }) @Retention(RetentionPolicy.SOURCE) public @interface BrightnessMaxReason {} Loading services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java +1 −1 Original line number Diff line number Diff line Loading @@ -347,7 +347,7 @@ public class BrightnessClamperController { data.mDisplayDeviceConfig)); } if (flags.useNewHdrBrightnessModifier()) { modifiers.add(new HdrBrightnessModifier(handler, listener, data)); modifiers.add(new HdrBrightnessModifier(handler, context, listener, data)); } return modifiers; } Loading services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java +116 −32 Original line number Diff line number Diff line Loading @@ -21,10 +21,15 @@ import static com.android.server.display.brightness.clamper.LightSensorControlle import android.annotation.Nullable; import android.annotation.SuppressLint; import android.content.Context; import android.database.ContentObserver; import android.hardware.display.DisplayManagerInternal; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; import android.os.UserHandle; import android.provider.Settings; import android.view.SurfaceControlHdrLayerInfoListener; import com.android.internal.annotations.VisibleForTesting; Loading @@ -44,6 +49,11 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, static final float DEFAULT_MAX_HDR_SDR_RATIO = 1.0f; private static final float DEFAULT_HDR_LAYER_SIZE = -1.0f; private final Uri mLowPowerModeSetting = Settings.Global.getUriFor( Settings.Global.LOW_POWER_MODE); private final ContentObserver mContentObserver; private final SurfaceControlHdrLayerInfoListener mHdrListener = new SurfaceControlHdrLayerInfoListener() { @Override Loading @@ -52,7 +62,8 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, boolean hdrLayerPresent = numberOfHdrLayers > 0; mHandler.post(() -> HdrBrightnessModifier.this.onHdrInfoChanged( hdrLayerPresent ? (float) (maxW * maxH) : DEFAULT_HDR_LAYER_SIZE, hdrLayerPresent ? maxDesiredHdrSdrRatio : DEFAULT_MAX_HDR_SDR_RATIO)); hdrLayerPresent ? Math.max(maxDesiredHdrSdrRatio, DEFAULT_MAX_HDR_SDR_RATIO) : DEFAULT_MAX_HDR_SDR_RATIO)); } }; Loading @@ -62,6 +73,7 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private final Runnable mDebouncer; private IBinder mRegisteredDisplayToken; private boolean mContentObserverRegistered = false; private DisplayDeviceConfig mDisplayDeviceConfig; @Nullable Loading @@ -73,6 +85,8 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private float mAmbientLux = INVALID_LUX; private boolean mLowPowerMode = false; private Mode mMode = Mode.NO_HDR; // The maximum brightness allowed for current lux private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX; Loading @@ -81,17 +95,17 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private float mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; private float mPendingTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; HdrBrightnessModifier(Handler handler, HdrBrightnessModifier(Handler handler, Context context, BrightnessClamperController.ClamperChangeListener clamperChangeListener, BrightnessClamperController.DisplayDeviceData displayData) { this(new Handler(handler.getLooper()), clamperChangeListener, new Injector(), displayData); this(new Handler(handler.getLooper()), clamperChangeListener, new Injector(context), displayData); } @VisibleForTesting HdrBrightnessModifier(Handler handler, BrightnessClamperController.ClamperChangeListener clamperChangeListener, Injector injector, BrightnessClamperController.DisplayDeviceData displayData) { Injector injector, BrightnessClamperController.DisplayDeviceData displayData) { mHandler = handler; mClamperChangeListener = clamperChangeListener; mInjector = injector; Loading @@ -100,6 +114,12 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, mMaxBrightness = mPendingMaxBrightness; mClamperChangeListener.onChanged(); }; mContentObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { onLowPowerModeChange(); } }; mHandler.post(() -> onDisplayChanged(displayData)); } Loading Loading @@ -135,12 +155,14 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, pw.println(" mMaxDesiredHdrRatio=" + mMaxDesiredHdrRatio); pw.println(" mHdrLayerSize=" + mHdrLayerSize); pw.println(" mAmbientLux=" + mAmbientLux); pw.println(" mLowPowerMode=" + mLowPowerMode); pw.println(" mMode=" + mMode); pw.println(" mMaxBrightness=" + mMaxBrightness); pw.println(" mPendingMaxBrightness=" + mPendingMaxBrightness); pw.println(" mTransitionRate=" + mTransitionRate); pw.println(" mPendingTransitionRate=" + mPendingTransitionRate); pw.println(" mHdrListener registered=" + (mRegisteredDisplayToken != null)); pw.println(" mContentObserverRegistered=" + mContentObserverRegistered); } // Called in DisplayControllerHandler Loading Loading @@ -182,7 +204,25 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } else { registerHdrListener(displayData.mDisplayToken); } recalculate(data, mMaxDesiredHdrRatio); if (data == null || data.allowInLowPowerMode) { unregisterContentObserver(); } else { registerContentObserver(); } Mode newMode = recalculateMode(data); // mode changed, or mode was HDR and HdrBrightnessData changed boolean needToNotifyChange = mMode != newMode || (mMode != HdrBrightnessModifier.Mode.NO_HDR && data != mHdrBrightnessData); mMode = newMode; mHdrBrightnessData = data; mMaxBrightness = findBrightnessLimit(mHdrBrightnessData, mAmbientLux); if (needToNotifyChange) { // data changed, reset custom transition rate mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } // Called in DisplayControllerHandler, when any modifier state changes Loading Loading @@ -225,30 +265,6 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, // && expectedMaxBrightness != mMaxBrightness } // Called in DisplayControllerHandler private void recalculate(@Nullable HdrBrightnessData data, float maxDesiredHdrRatio) { Mode newMode = recalculateMode(data); // if HDR mode changed, notify changed boolean needToNotifyChange = mMode != newMode; // If HDR mode is active, we need to check if other HDR params are changed if (mMode != HdrBrightnessModifier.Mode.NO_HDR) { if (!BrightnessSynchronizer.floatEquals(mMaxDesiredHdrRatio, maxDesiredHdrRatio) || data != mHdrBrightnessData) { needToNotifyChange = true; } } mMode = newMode; mHdrBrightnessData = data; mMaxDesiredHdrRatio = maxDesiredHdrRatio; if (needToNotifyChange) { // data or hdr layer changed, reset custom transition rate mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } // Called in DisplayControllerHandler private Mode recalculateMode(@Nullable HdrBrightnessData data) { // no config Loading @@ -259,6 +275,10 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, if (mHdrLayerSize == DEFAULT_HDR_LAYER_SIZE) { return Mode.NO_HDR; } // low power mode and not allowed in low power mode if (!data.allowInLowPowerMode && mLowPowerMode) { return Mode.NO_HDR; } // HDR layer < minHdr % for Nbm if (mHdrLayerSize < mScreenSize * data.minimumHdrPercentOfScreenForNbm) { return Mode.NO_HDR; Loading @@ -271,6 +291,16 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, return Mode.HBM_HDR; } private void onLowPowerModeChange() { mLowPowerMode = mInjector.isLowPowerMode(); Mode newMode = recalculateMode(mHdrBrightnessData); if (newMode != mMode) { mMode = newMode; mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } private float getMaxBrightness(Mode mode, float maxBrightness, HdrBrightnessData data) { if (mode == Mode.NBM_HDR) { return Math.min(data.hbmTransitionPoint, maxBrightness); Loading @@ -282,7 +312,13 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } // Called in DisplayControllerHandler private float findBrightnessLimit(HdrBrightnessData data, float ambientLux) { private float findBrightnessLimit(@Nullable HdrBrightnessData data, float ambientLux) { if (data == null) { return PowerManager.BRIGHTNESS_MAX; } if (ambientLux == INVALID_LUX) { return PowerManager.BRIGHTNESS_MAX; } float foundAmbientBoundary = Float.MAX_VALUE; float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX; for (Map.Entry<Float, Float> brightnessPoint : Loading @@ -300,7 +336,17 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, // Called in DisplayControllerHandler private void onHdrInfoChanged(float hdrLayerSize, float maxDesiredHdrSdrRatio) { mHdrLayerSize = hdrLayerSize; recalculate(mHdrBrightnessData, maxDesiredHdrSdrRatio); Mode newMode = recalculateMode(mHdrBrightnessData); // mode changed, or mode was HDR and maxDesiredHdrRatio changed boolean needToNotifyChange = mMode != newMode || (mMode != HdrBrightnessModifier.Mode.NO_HDR && !BrightnessSynchronizer.floatEquals(mMaxDesiredHdrRatio, maxDesiredHdrSdrRatio)); mMode = newMode; mMaxDesiredHdrRatio = maxDesiredHdrSdrRatio; if (needToNotifyChange) { mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } // Called in DisplayControllerHandler Loading @@ -324,12 +370,36 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } } // Called in DisplayControllerHandler private void registerContentObserver() { if (!mContentObserverRegistered) { mInjector.registerContentObserver(mContentObserver, mLowPowerModeSetting); mContentObserverRegistered = true; mLowPowerMode = mInjector.isLowPowerMode(); } } // Called in DisplayControllerHandler private void unregisterContentObserver() { if (mContentObserverRegistered) { mInjector.unregisterContentObserver(mContentObserver); mContentObserverRegistered = false; mLowPowerMode = false; } } private enum Mode { NO_HDR, NBM_HDR, HBM_HDR } @SuppressLint("MissingPermission") static class Injector { private final Context mContext; Injector(Context context) { mContext = context; } void registerHdrListener(SurfaceControlHdrLayerInfoListener listener, IBinder token) { listener.register(token); } Loading @@ -337,5 +407,19 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, void unregisterHdrListener(SurfaceControlHdrLayerInfoListener listener, IBinder token) { listener.unregister(token); } void registerContentObserver(ContentObserver observer, Uri uri) { mContext.getContentResolver().registerContentObserver(uri, false, observer, UserHandle.USER_ALL); } void unregisterContentObserver(ContentObserver observer) { mContext.getContentResolver().unregisterContentObserver(observer); } boolean isLowPowerMode() { return Settings.Global.getInt( mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, 0) != 0; } } } services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrBrightnessModifierTest.kt +73 −22 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package com.android.server.display.brightness.clamper import android.content.Context import android.database.ContentObserver import android.hardware.display.DisplayManagerInternal import android.net.Uri import android.os.IBinder import android.os.PowerManager.BRIGHTNESS_MAX import android.util.Spline Loading Loading @@ -51,7 +54,7 @@ class HdrBrightnessModifierTest { private val stoppedClock = OffsettableClock.Stopped() private val testHandler = TestHandler(null, stoppedClock) private val testInjector = TestInjector() private val testInjector = TestInjector(mock<Context>()) private val mockChangeListener = mock<ClamperChangeListener>() private val mockDisplayDeviceConfig = mock<DisplayDeviceConfig>() private val mockDisplayBinder = mock<IBinder>() Loading @@ -63,14 +66,14 @@ class HdrBrightnessModifierTest { private val dummyData = createDisplayDeviceData(mockDisplayDeviceConfig, mockDisplayBinder) @Test fun `change listener is not called on init`() { fun changeListenerIsNotCalledOnInit() { initHdrModifier() verify(mockChangeListener, never()).onChanged() } @Test fun `hdr listener registered on init if hdr data is present`() { fun hdrListenerRegisteredOnInit_hdrDataPresent() { initHdrModifier() assertThat(testInjector.registeredHdrListener).isNotNull() Loading @@ -78,22 +81,19 @@ class HdrBrightnessModifierTest { } @Test fun `hdr listener not registered on init if hdr data is missing`() { initHdrModifier(null) testHandler.flush() fun hdrListenerNotRegisteredOnInit_hdrDataMissing() { initHdrModifier(hdrBrightnessData = null) assertThat(testInjector.registeredHdrListener).isNull() assertThat(testInjector.registeredToken).isNull() } @Test fun `unsubscribes hdr listener when display changed with no hdr data`() { fun unsubscribeHdrListener_displayChangedWithNoHdrData() { initHdrModifier() whenever(mockDisplayDeviceConfig.hdrBrightnessData).thenReturn(null) modifier.onDisplayChanged(dummyData) testHandler.flush() assertThat(testInjector.registeredHdrListener).isNull() assertThat(testInjector.registeredToken).isNull() Loading @@ -101,12 +101,11 @@ class HdrBrightnessModifierTest { } @Test fun `resubscribes hdr listener when display changed with different token`() { fun resubscribesHdrListener_displayChangedWithDifferentToken() { initHdrModifier() modifier.onDisplayChanged( createDisplayDeviceData(mockDisplayDeviceConfig, mockDisplayBinderOther)) testHandler.flush() assertThat(testInjector.registeredHdrListener).isNotNull() assertThat(testInjector.registeredToken).isEqualTo(mockDisplayBinderOther) Loading @@ -114,7 +113,28 @@ class HdrBrightnessModifierTest { } @Test fun `test NO_HDR mode`() { fun contentObserverNotRegisteredOnInit_hdrDataMissing() { initHdrModifier(null) assertThat(testInjector.registeredContentObserver).isNull() } @Test fun contentObserverNotRegisteredOnInit_allowedInLowPowerMode() { initHdrModifier(createHdrBrightnessData(allowInLowPowerMode = true)) assertThat(testInjector.registeredContentObserver).isNull() } @Test fun contentObserverRegisteredOnInit_notAllowedInLowPowerMode() { initHdrModifier(createHdrBrightnessData(allowInLowPowerMode = false)) assertThat(testInjector.registeredContentObserver).isNotNull() } @Test fun testNoHdrMode() { initHdrModifier() // screen size = 10_000 setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -131,7 +151,7 @@ class HdrBrightnessModifierTest { } @Test fun `test NBM_HDR mode`() { fun testNbmHdrMode() { initHdrModifier() // screen size = 10_000 val transitionPoint = 0.55f Loading @@ -157,7 +177,7 @@ class HdrBrightnessModifierTest { } @Test fun `test HBM_HDR mode`() { fun testHbmHdrMode() { initHdrModifier() // screen size = 10_000 setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -182,7 +202,7 @@ class HdrBrightnessModifierTest { } @Test fun `test display change no HDR content`() { fun testDisplayChange_noHdrContent() { initHdrModifier() setupDisplay(width = 100, height = 100) assertModifierState() Loading @@ -195,7 +215,7 @@ class HdrBrightnessModifierTest { } @Test fun `test display change with HDR content`() { fun testDisplayChange_hdrContent() { initHdrModifier() setupDisplay(width = 100, height = 100) setupHdrLayer(width = 100, height = 100, maxHdrRatio = 5f) Loading @@ -218,7 +238,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease above maxBrightnessLimits no HDR`() { fun testSetAmbientLux_decreaseAboveMaxBrightnessLimitNoHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -234,7 +254,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease above maxBrightnessLimits with HDR`() { fun testSetAmbientLux_decreaseAboveMaxBrightnessLimitWithHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 200, height = 200, hdrBrightnessData = createHdrBrightnessData( Loading @@ -260,7 +280,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease below maxBrightnessLimits no HDR`() { fun testSetAmbientLux_decreaseBelowMaxBrightnessLimitNoHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -276,7 +296,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease below maxBrightnessLimits with HDR`() { fun testSetAmbientLux_decreaseBelowMaxBrightnessLimitWithHdr() { initHdrModifier() modifier.setAmbientLux(1000f) val maxBrightness = 0.6f Loading Loading @@ -322,6 +342,23 @@ class HdrBrightnessModifierTest { ) } @Test fun testLowPower_notAllowedInLowPower() { initHdrModifier() setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( allowInLowPowerMode = false )) setupHdrLayer(width = 100, height = 100) clearInvocations(mockChangeListener) testInjector.isLowPower = true testInjector.registeredContentObserver!!.onChange(true) verify(mockChangeListener).onChanged() assertModifierState() } // Helper functions private fun setupHdrLayer(width: Int = 100, height: Int = 100, maxHdrRatio: Float = 0.8f) { testInjector.registeredHdrListener!!.onHdrInfoChanged( mockDisplayBinder, 1, width, height, 0, maxHdrRatio Loading @@ -345,7 +382,6 @@ class HdrBrightnessModifierTest { width = width, height = height )) testHandler.flush() } private fun initHdrModifier(hdrBrightnessData: HdrBrightnessData? = createHdrBrightnessData()) { Loading Loading @@ -384,9 +420,12 @@ class HdrBrightnessModifierTest { assertThat(stateBuilder.customAnimationRate).isEqualTo(animationRate) } internal class TestInjector : Injector() { internal class TestInjector(context: Context) : Injector(context) { var registeredHdrListener: SurfaceControlHdrLayerInfoListener? = null var registeredToken: IBinder? = null var registeredContentObserver: ContentObserver? = null var isLowPower: Boolean = false override fun registerHdrListener( listener: SurfaceControlHdrLayerInfoListener, token: IBinder Loading @@ -401,5 +440,17 @@ class HdrBrightnessModifierTest { registeredHdrListener = null registeredToken = null } override fun registerContentObserver(observer: ContentObserver, uri: Uri) { registeredContentObserver = observer } override fun unregisterContentObserver(observer: ContentObserver) { registeredContentObserver = null } override fun isLowPowerMode(): Boolean { return isLowPower } } } No newline at end of file Loading
core/java/android/hardware/display/BrightnessInfo.java +2 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,8 @@ public final class BrightnessInfo implements Parcelable { @IntDef(prefix = {"BRIGHTNESS_MAX_REASON_"}, value = { BRIGHTNESS_MAX_REASON_NONE, BRIGHTNESS_MAX_REASON_THERMAL, BRIGHTNESS_MAX_REASON_POWER_IC BRIGHTNESS_MAX_REASON_POWER_IC, BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE }) @Retention(RetentionPolicy.SOURCE) public @interface BrightnessMaxReason {} Loading
services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java +1 −1 Original line number Diff line number Diff line Loading @@ -347,7 +347,7 @@ public class BrightnessClamperController { data.mDisplayDeviceConfig)); } if (flags.useNewHdrBrightnessModifier()) { modifiers.add(new HdrBrightnessModifier(handler, listener, data)); modifiers.add(new HdrBrightnessModifier(handler, context, listener, data)); } return modifiers; } Loading
services/core/java/com/android/server/display/brightness/clamper/HdrBrightnessModifier.java +116 −32 Original line number Diff line number Diff line Loading @@ -21,10 +21,15 @@ import static com.android.server.display.brightness.clamper.LightSensorControlle import android.annotation.Nullable; import android.annotation.SuppressLint; import android.content.Context; import android.database.ContentObserver; import android.hardware.display.DisplayManagerInternal; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; import android.os.UserHandle; import android.provider.Settings; import android.view.SurfaceControlHdrLayerInfoListener; import com.android.internal.annotations.VisibleForTesting; Loading @@ -44,6 +49,11 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, static final float DEFAULT_MAX_HDR_SDR_RATIO = 1.0f; private static final float DEFAULT_HDR_LAYER_SIZE = -1.0f; private final Uri mLowPowerModeSetting = Settings.Global.getUriFor( Settings.Global.LOW_POWER_MODE); private final ContentObserver mContentObserver; private final SurfaceControlHdrLayerInfoListener mHdrListener = new SurfaceControlHdrLayerInfoListener() { @Override Loading @@ -52,7 +62,8 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, boolean hdrLayerPresent = numberOfHdrLayers > 0; mHandler.post(() -> HdrBrightnessModifier.this.onHdrInfoChanged( hdrLayerPresent ? (float) (maxW * maxH) : DEFAULT_HDR_LAYER_SIZE, hdrLayerPresent ? maxDesiredHdrSdrRatio : DEFAULT_MAX_HDR_SDR_RATIO)); hdrLayerPresent ? Math.max(maxDesiredHdrSdrRatio, DEFAULT_MAX_HDR_SDR_RATIO) : DEFAULT_MAX_HDR_SDR_RATIO)); } }; Loading @@ -62,6 +73,7 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private final Runnable mDebouncer; private IBinder mRegisteredDisplayToken; private boolean mContentObserverRegistered = false; private DisplayDeviceConfig mDisplayDeviceConfig; @Nullable Loading @@ -73,6 +85,8 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private float mAmbientLux = INVALID_LUX; private boolean mLowPowerMode = false; private Mode mMode = Mode.NO_HDR; // The maximum brightness allowed for current lux private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX; Loading @@ -81,17 +95,17 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, private float mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; private float mPendingTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; HdrBrightnessModifier(Handler handler, HdrBrightnessModifier(Handler handler, Context context, BrightnessClamperController.ClamperChangeListener clamperChangeListener, BrightnessClamperController.DisplayDeviceData displayData) { this(new Handler(handler.getLooper()), clamperChangeListener, new Injector(), displayData); this(new Handler(handler.getLooper()), clamperChangeListener, new Injector(context), displayData); } @VisibleForTesting HdrBrightnessModifier(Handler handler, BrightnessClamperController.ClamperChangeListener clamperChangeListener, Injector injector, BrightnessClamperController.DisplayDeviceData displayData) { Injector injector, BrightnessClamperController.DisplayDeviceData displayData) { mHandler = handler; mClamperChangeListener = clamperChangeListener; mInjector = injector; Loading @@ -100,6 +114,12 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, mMaxBrightness = mPendingMaxBrightness; mClamperChangeListener.onChanged(); }; mContentObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { onLowPowerModeChange(); } }; mHandler.post(() -> onDisplayChanged(displayData)); } Loading Loading @@ -135,12 +155,14 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, pw.println(" mMaxDesiredHdrRatio=" + mMaxDesiredHdrRatio); pw.println(" mHdrLayerSize=" + mHdrLayerSize); pw.println(" mAmbientLux=" + mAmbientLux); pw.println(" mLowPowerMode=" + mLowPowerMode); pw.println(" mMode=" + mMode); pw.println(" mMaxBrightness=" + mMaxBrightness); pw.println(" mPendingMaxBrightness=" + mPendingMaxBrightness); pw.println(" mTransitionRate=" + mTransitionRate); pw.println(" mPendingTransitionRate=" + mPendingTransitionRate); pw.println(" mHdrListener registered=" + (mRegisteredDisplayToken != null)); pw.println(" mContentObserverRegistered=" + mContentObserverRegistered); } // Called in DisplayControllerHandler Loading Loading @@ -182,7 +204,25 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } else { registerHdrListener(displayData.mDisplayToken); } recalculate(data, mMaxDesiredHdrRatio); if (data == null || data.allowInLowPowerMode) { unregisterContentObserver(); } else { registerContentObserver(); } Mode newMode = recalculateMode(data); // mode changed, or mode was HDR and HdrBrightnessData changed boolean needToNotifyChange = mMode != newMode || (mMode != HdrBrightnessModifier.Mode.NO_HDR && data != mHdrBrightnessData); mMode = newMode; mHdrBrightnessData = data; mMaxBrightness = findBrightnessLimit(mHdrBrightnessData, mAmbientLux); if (needToNotifyChange) { // data changed, reset custom transition rate mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } // Called in DisplayControllerHandler, when any modifier state changes Loading Loading @@ -225,30 +265,6 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, // && expectedMaxBrightness != mMaxBrightness } // Called in DisplayControllerHandler private void recalculate(@Nullable HdrBrightnessData data, float maxDesiredHdrRatio) { Mode newMode = recalculateMode(data); // if HDR mode changed, notify changed boolean needToNotifyChange = mMode != newMode; // If HDR mode is active, we need to check if other HDR params are changed if (mMode != HdrBrightnessModifier.Mode.NO_HDR) { if (!BrightnessSynchronizer.floatEquals(mMaxDesiredHdrRatio, maxDesiredHdrRatio) || data != mHdrBrightnessData) { needToNotifyChange = true; } } mMode = newMode; mHdrBrightnessData = data; mMaxDesiredHdrRatio = maxDesiredHdrRatio; if (needToNotifyChange) { // data or hdr layer changed, reset custom transition rate mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } // Called in DisplayControllerHandler private Mode recalculateMode(@Nullable HdrBrightnessData data) { // no config Loading @@ -259,6 +275,10 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, if (mHdrLayerSize == DEFAULT_HDR_LAYER_SIZE) { return Mode.NO_HDR; } // low power mode and not allowed in low power mode if (!data.allowInLowPowerMode && mLowPowerMode) { return Mode.NO_HDR; } // HDR layer < minHdr % for Nbm if (mHdrLayerSize < mScreenSize * data.minimumHdrPercentOfScreenForNbm) { return Mode.NO_HDR; Loading @@ -271,6 +291,16 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, return Mode.HBM_HDR; } private void onLowPowerModeChange() { mLowPowerMode = mInjector.isLowPowerMode(); Mode newMode = recalculateMode(mHdrBrightnessData); if (newMode != mMode) { mMode = newMode; mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } private float getMaxBrightness(Mode mode, float maxBrightness, HdrBrightnessData data) { if (mode == Mode.NBM_HDR) { return Math.min(data.hbmTransitionPoint, maxBrightness); Loading @@ -282,7 +312,13 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } // Called in DisplayControllerHandler private float findBrightnessLimit(HdrBrightnessData data, float ambientLux) { private float findBrightnessLimit(@Nullable HdrBrightnessData data, float ambientLux) { if (data == null) { return PowerManager.BRIGHTNESS_MAX; } if (ambientLux == INVALID_LUX) { return PowerManager.BRIGHTNESS_MAX; } float foundAmbientBoundary = Float.MAX_VALUE; float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX; for (Map.Entry<Float, Float> brightnessPoint : Loading @@ -300,7 +336,17 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, // Called in DisplayControllerHandler private void onHdrInfoChanged(float hdrLayerSize, float maxDesiredHdrSdrRatio) { mHdrLayerSize = hdrLayerSize; recalculate(mHdrBrightnessData, maxDesiredHdrSdrRatio); Mode newMode = recalculateMode(mHdrBrightnessData); // mode changed, or mode was HDR and maxDesiredHdrRatio changed boolean needToNotifyChange = mMode != newMode || (mMode != HdrBrightnessModifier.Mode.NO_HDR && !BrightnessSynchronizer.floatEquals(mMaxDesiredHdrRatio, maxDesiredHdrSdrRatio)); mMode = newMode; mMaxDesiredHdrRatio = maxDesiredHdrSdrRatio; if (needToNotifyChange) { mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET; mClamperChangeListener.onChanged(); } } // Called in DisplayControllerHandler Loading @@ -324,12 +370,36 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, } } // Called in DisplayControllerHandler private void registerContentObserver() { if (!mContentObserverRegistered) { mInjector.registerContentObserver(mContentObserver, mLowPowerModeSetting); mContentObserverRegistered = true; mLowPowerMode = mInjector.isLowPowerMode(); } } // Called in DisplayControllerHandler private void unregisterContentObserver() { if (mContentObserverRegistered) { mInjector.unregisterContentObserver(mContentObserver); mContentObserverRegistered = false; mLowPowerMode = false; } } private enum Mode { NO_HDR, NBM_HDR, HBM_HDR } @SuppressLint("MissingPermission") static class Injector { private final Context mContext; Injector(Context context) { mContext = context; } void registerHdrListener(SurfaceControlHdrLayerInfoListener listener, IBinder token) { listener.register(token); } Loading @@ -337,5 +407,19 @@ public class HdrBrightnessModifier implements BrightnessStateModifier, void unregisterHdrListener(SurfaceControlHdrLayerInfoListener listener, IBinder token) { listener.unregister(token); } void registerContentObserver(ContentObserver observer, Uri uri) { mContext.getContentResolver().registerContentObserver(uri, false, observer, UserHandle.USER_ALL); } void unregisterContentObserver(ContentObserver observer) { mContext.getContentResolver().unregisterContentObserver(observer); } boolean isLowPowerMode() { return Settings.Global.getInt( mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, 0) != 0; } } }
services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/HdrBrightnessModifierTest.kt +73 −22 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package com.android.server.display.brightness.clamper import android.content.Context import android.database.ContentObserver import android.hardware.display.DisplayManagerInternal import android.net.Uri import android.os.IBinder import android.os.PowerManager.BRIGHTNESS_MAX import android.util.Spline Loading Loading @@ -51,7 +54,7 @@ class HdrBrightnessModifierTest { private val stoppedClock = OffsettableClock.Stopped() private val testHandler = TestHandler(null, stoppedClock) private val testInjector = TestInjector() private val testInjector = TestInjector(mock<Context>()) private val mockChangeListener = mock<ClamperChangeListener>() private val mockDisplayDeviceConfig = mock<DisplayDeviceConfig>() private val mockDisplayBinder = mock<IBinder>() Loading @@ -63,14 +66,14 @@ class HdrBrightnessModifierTest { private val dummyData = createDisplayDeviceData(mockDisplayDeviceConfig, mockDisplayBinder) @Test fun `change listener is not called on init`() { fun changeListenerIsNotCalledOnInit() { initHdrModifier() verify(mockChangeListener, never()).onChanged() } @Test fun `hdr listener registered on init if hdr data is present`() { fun hdrListenerRegisteredOnInit_hdrDataPresent() { initHdrModifier() assertThat(testInjector.registeredHdrListener).isNotNull() Loading @@ -78,22 +81,19 @@ class HdrBrightnessModifierTest { } @Test fun `hdr listener not registered on init if hdr data is missing`() { initHdrModifier(null) testHandler.flush() fun hdrListenerNotRegisteredOnInit_hdrDataMissing() { initHdrModifier(hdrBrightnessData = null) assertThat(testInjector.registeredHdrListener).isNull() assertThat(testInjector.registeredToken).isNull() } @Test fun `unsubscribes hdr listener when display changed with no hdr data`() { fun unsubscribeHdrListener_displayChangedWithNoHdrData() { initHdrModifier() whenever(mockDisplayDeviceConfig.hdrBrightnessData).thenReturn(null) modifier.onDisplayChanged(dummyData) testHandler.flush() assertThat(testInjector.registeredHdrListener).isNull() assertThat(testInjector.registeredToken).isNull() Loading @@ -101,12 +101,11 @@ class HdrBrightnessModifierTest { } @Test fun `resubscribes hdr listener when display changed with different token`() { fun resubscribesHdrListener_displayChangedWithDifferentToken() { initHdrModifier() modifier.onDisplayChanged( createDisplayDeviceData(mockDisplayDeviceConfig, mockDisplayBinderOther)) testHandler.flush() assertThat(testInjector.registeredHdrListener).isNotNull() assertThat(testInjector.registeredToken).isEqualTo(mockDisplayBinderOther) Loading @@ -114,7 +113,28 @@ class HdrBrightnessModifierTest { } @Test fun `test NO_HDR mode`() { fun contentObserverNotRegisteredOnInit_hdrDataMissing() { initHdrModifier(null) assertThat(testInjector.registeredContentObserver).isNull() } @Test fun contentObserverNotRegisteredOnInit_allowedInLowPowerMode() { initHdrModifier(createHdrBrightnessData(allowInLowPowerMode = true)) assertThat(testInjector.registeredContentObserver).isNull() } @Test fun contentObserverRegisteredOnInit_notAllowedInLowPowerMode() { initHdrModifier(createHdrBrightnessData(allowInLowPowerMode = false)) assertThat(testInjector.registeredContentObserver).isNotNull() } @Test fun testNoHdrMode() { initHdrModifier() // screen size = 10_000 setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -131,7 +151,7 @@ class HdrBrightnessModifierTest { } @Test fun `test NBM_HDR mode`() { fun testNbmHdrMode() { initHdrModifier() // screen size = 10_000 val transitionPoint = 0.55f Loading @@ -157,7 +177,7 @@ class HdrBrightnessModifierTest { } @Test fun `test HBM_HDR mode`() { fun testHbmHdrMode() { initHdrModifier() // screen size = 10_000 setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -182,7 +202,7 @@ class HdrBrightnessModifierTest { } @Test fun `test display change no HDR content`() { fun testDisplayChange_noHdrContent() { initHdrModifier() setupDisplay(width = 100, height = 100) assertModifierState() Loading @@ -195,7 +215,7 @@ class HdrBrightnessModifierTest { } @Test fun `test display change with HDR content`() { fun testDisplayChange_hdrContent() { initHdrModifier() setupDisplay(width = 100, height = 100) setupHdrLayer(width = 100, height = 100, maxHdrRatio = 5f) Loading @@ -218,7 +238,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease above maxBrightnessLimits no HDR`() { fun testSetAmbientLux_decreaseAboveMaxBrightnessLimitNoHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -234,7 +254,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease above maxBrightnessLimits with HDR`() { fun testSetAmbientLux_decreaseAboveMaxBrightnessLimitWithHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 200, height = 200, hdrBrightnessData = createHdrBrightnessData( Loading @@ -260,7 +280,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease below maxBrightnessLimits no HDR`() { fun testSetAmbientLux_decreaseBelowMaxBrightnessLimitNoHdr() { initHdrModifier() modifier.setAmbientLux(1000f) setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( Loading @@ -276,7 +296,7 @@ class HdrBrightnessModifierTest { } @Test fun `test ambient lux decrease below maxBrightnessLimits with HDR`() { fun testSetAmbientLux_decreaseBelowMaxBrightnessLimitWithHdr() { initHdrModifier() modifier.setAmbientLux(1000f) val maxBrightness = 0.6f Loading Loading @@ -322,6 +342,23 @@ class HdrBrightnessModifierTest { ) } @Test fun testLowPower_notAllowedInLowPower() { initHdrModifier() setupDisplay(width = 100, height = 100, hdrBrightnessData = createHdrBrightnessData( allowInLowPowerMode = false )) setupHdrLayer(width = 100, height = 100) clearInvocations(mockChangeListener) testInjector.isLowPower = true testInjector.registeredContentObserver!!.onChange(true) verify(mockChangeListener).onChanged() assertModifierState() } // Helper functions private fun setupHdrLayer(width: Int = 100, height: Int = 100, maxHdrRatio: Float = 0.8f) { testInjector.registeredHdrListener!!.onHdrInfoChanged( mockDisplayBinder, 1, width, height, 0, maxHdrRatio Loading @@ -345,7 +382,6 @@ class HdrBrightnessModifierTest { width = width, height = height )) testHandler.flush() } private fun initHdrModifier(hdrBrightnessData: HdrBrightnessData? = createHdrBrightnessData()) { Loading Loading @@ -384,9 +420,12 @@ class HdrBrightnessModifierTest { assertThat(stateBuilder.customAnimationRate).isEqualTo(animationRate) } internal class TestInjector : Injector() { internal class TestInjector(context: Context) : Injector(context) { var registeredHdrListener: SurfaceControlHdrLayerInfoListener? = null var registeredToken: IBinder? = null var registeredContentObserver: ContentObserver? = null var isLowPower: Boolean = false override fun registerHdrListener( listener: SurfaceControlHdrLayerInfoListener, token: IBinder Loading @@ -401,5 +440,17 @@ class HdrBrightnessModifierTest { registeredHdrListener = null registeredToken = null } override fun registerContentObserver(observer: ContentObserver, uri: Uri) { registeredContentObserver = observer } override fun unregisterContentObserver(observer: ContentObserver) { registeredContentObserver = null } override fun isLowPowerMode(): Boolean { return isLowPower } } } No newline at end of file