Loading services/core/java/com/android/server/display/AutomaticBrightnessController.java +77 −30 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.display; import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; import static com.android.internal.display.BrightnessUtils.convertLinearToGamma; import static com.android.server.display.BrightnessMappingStrategy.INVALID_LUX; import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString; Loading Loading @@ -57,6 +58,7 @@ import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.os.BackgroundThread; import com.android.server.EventLogTags; import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.brightness.BrightnessUtils; import com.android.server.display.brightness.clamper.BrightnessClamperController; import com.android.server.display.config.HysteresisLevels; import com.android.server.display.feature.DisplayManagerFlags; Loading Loading @@ -112,6 +114,11 @@ public class AutomaticBrightnessController { private static final int MSG_RUN_UPDATE = 6; private static final int MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL = 7; // If our traditional math determines that the brightness is too small to actually change, // then also check if brightness percent would change at least the amount of this value, // and if so, move forward with the change. In 0-100 percent scale. private static final float MINIMUM_BRIGHTNESS_PERCENT_CHANGE = .4f; // Callbacks for requesting updates to the display's power state private final Callbacks mCallbacks; Loading Loading @@ -1009,13 +1016,31 @@ public class AutomaticBrightnessController { } return; } if (!BrightnessSynchronizer.floatEquals(mScreenAutoBrightness, newScreenAutoBrightness)) { // Return early if the brightness didn't actually change. if (BrightnessSynchronizer.floatEquals(mScreenAutoBrightness, newScreenAutoBrightness)) { // Because brightness itself is in a logarithmic scale, the values at the low end // are so low that the difference between 0% and 2% might be within the float comparison // EPSILON value. To combat this, we do a secondary check on the percent change in // brightness. final float oldPercent = getBrightnessAsPercent(mScreenAutoBrightness); final float newPercent = getBrightnessAsPercent(newScreenAutoBrightness); final boolean isBrightnessPercentDifferent = !Float.isNaN(oldPercent) && !Float.isNaN(newPercent) && (Math.abs(oldPercent - newPercent) > MINIMUM_BRIGHTNESS_PERCENT_CHANGE); if (!isBrightnessPercentDifferent) { // Brightness percent didn't change either, so lets return early here. return; } } if (mLoggingEnabled) { Slog.d(TAG, "updateAutoBrightness: " + "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " + "newScreenAutoBrightness=" + newScreenAutoBrightness); } if (!withinThreshold) { mPreThresholdBrightness = mScreenAutoBrightness; } Loading @@ -1039,14 +1064,36 @@ public class AutomaticBrightnessController { mCallbacks.updateBrightness(); } } /** * @return specified brightness value as a [0-100] percent taking current * min/max constraints into account. */ private float getBrightnessAsPercent(float brightness) { if (!BrightnessUtils.isValidBrightnessValue(brightness)) { return PowerManager.BRIGHTNESS_INVALID_FLOAT; } return 100.0f * convertLinearToGamma(MathUtils.constrainedMap( mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum, getMinBrightness(), getMaxBrightness(), brightness)); } // Clamps values with float range [0.0-1.0] private float clampScreenBrightness(float value) { final float minBrightness = mBrightnessRangeController.getCurrentBrightnessMin(); final float maxBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMax(), return MathUtils.constrain(value, getMinBrightness(), getMaxBrightness()); } private float getMinBrightness() { return Math.max(mBrightnessRangeController.getCurrentBrightnessMin(), mBrightnessClamperController.getMinBrightness()); } private float getMaxBrightness() { return Math.min(mBrightnessRangeController.getCurrentBrightnessMax(), mBrightnessClamperController.getMaxBrightness()); return MathUtils.constrain(value, minBrightness, maxBrightness); } private void prepareBrightnessAdjustmentSample() { Loading services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java +8 −1 Original line number Diff line number Diff line Loading @@ -219,6 +219,10 @@ public class BrightnessClamperController { return mModifiersAggregatedState.mMaxBrightness; } public float getMinBrightness() { return mModifiersAggregatedState.mMinBrightness; } public boolean isThrottled() { return mModifiersAggregatedState.mMaxBrightnessReason != BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; Loading Loading @@ -246,7 +250,9 @@ public class BrightnessClamperController { || state1.mHdrRatioScaleFactor != state2.mHdrRatioScaleFactor || state1.mMaxBrightnessReason != state2.mMaxBrightnessReason || !BrightnessSynchronizer.floatEquals(state1.mMaxBrightness, state2.mMaxBrightness); state2.mMaxBrightness) || !BrightnessSynchronizer.floatEquals(state1.mMinBrightness, state2.mMinBrightness); } private void start() { Loading Loading @@ -484,5 +490,6 @@ public class BrightnessClamperController { @BrightnessInfo.BrightnessMaxReason int mMaxBrightnessReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; float mMaxBrightness = PowerManager.BRIGHTNESS_MAX; float mMinBrightness = PowerManager.BRIGHTNESS_MIN; } } services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java +11 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,8 @@ import java.io.PrintWriter; * lux conditions and user preferred minimum. */ public class BrightnessLowLuxModifier extends BrightnessModifier implements BrightnessClamperController.UserSwitchListener { BrightnessClamperController.UserSwitchListener, BrightnessClamperController.StatefulModifier { // To enable these logs, run: // 'adb shell setprop persist.log.tag.BrightnessLowLuxModifier DEBUG && adb reboot' Loading Loading @@ -155,7 +156,8 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements @Override public void apply(DisplayManagerInternal.DisplayPowerRequest request, DisplayBrightnessState.Builder stateBuilder) { stateBuilder.setMinBrightness(mBrightnessLowerBound); float minBrightness = Math.max(stateBuilder.getMinBrightness(), mBrightnessLowerBound); stateBuilder.setMinBrightness(minBrightness); float boundedBrightness = Math.max(mBrightnessLowerBound, stateBuilder.getBrightness()); stateBuilder.setBrightness(boundedBrightness); if (BrightnessSynchronizer.floatEquals(stateBuilder.getBrightness(), Loading @@ -164,6 +166,13 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements } } @Override public void applyStateChange(BrightnessClamperController.ModifiersAggregatedState state) { if (state.mMinBrightness < mBrightnessLowerBound) { state.mMinBrightness = mBrightnessLowerBound; } } @Override public void stop() { } Loading services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +74 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.os.Handler; import android.os.PowerManager; import android.os.SystemClock; import android.os.test.TestLooper; import android.util.MathUtils; import android.util.SparseArray; import android.view.Display; Loading @@ -55,6 +56,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.display.BrightnessUtils; import com.android.server.display.brightness.clamper.BrightnessClamperController; import com.android.server.display.config.HysteresisLevels; import com.android.server.display.feature.DisplayManagerFlags; Loading Loading @@ -798,6 +800,78 @@ public class AutomaticBrightnessControllerTest { assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getRawAutomaticScreenBrightness(), 0.0f); } /** * Tests that movement from 1% brightness to 0% brightness is possible. * Because of gamma conversion, the difference in float brightness between 0 and 1 * percent is very small and this ensures that our float-comparison (using EPSILON) * can tell the difference between the two small values. */ @Test public void testBrightnessChangeAtLowEnd() throws Exception { ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); SensorEventListener listener = listenerCaptor.getValue(); // Min and Max brightness may be reduced due to conditions such as ambient environment, // thermal, etc. So, lets further reduce the range of the brightness values since that // can also affect the floating-point comparison resolution. float minBrightness = 0.01f; float maxBrightness = 0.25f; when(mBrightnessRangeController.getCurrentBrightnessMax()).thenReturn(maxBrightness); when(mBrightnessRangeController.getCurrentBrightnessMin()).thenReturn(minBrightness); float twoPercentLux = 40; float twoPercent = 0.02f; float twoPercentLinearBrightness = MathUtils.lerp(minBrightness, maxBrightness, BrightnessUtils.convertGammaToLinear(twoPercent)); when(mBrightnessMappingStrategy.getBrightness(eq(twoPercentLux), eq(null), anyInt())) .thenReturn(twoPercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) twoPercentLux)); assertEquals(twoPercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(twoPercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); float onePercentLux = 20; float onePercent = 0.01f; float onePercentLinearBrightness = MathUtils.lerp(minBrightness, maxBrightness, BrightnessUtils.convertGammaToLinear(onePercent)); when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) .thenReturn(onePercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) onePercentLux)); assertEquals(onePercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(onePercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); // Make a small change down an ensure the brightness actually changes. float zeroPercentLux = 2; float zeroPercent = 0.00f; float zeroPercentLinearBrightness = MathUtils.lerp(minBrightness, maxBrightness, BrightnessUtils.convertGammaToLinear(zeroPercent)); when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) .thenReturn(zeroPercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) zeroPercentLux)); assertEquals(zeroPercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(zeroPercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); // And for good measure, lets put it back to 1% when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) .thenReturn(onePercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) onePercentLux)); assertEquals(onePercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(onePercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); } @Test public void testGetSensorReadings() throws Exception { ArgumentCaptor<SensorEventListener> listenerCaptor = Loading Loading
services/core/java/com/android/server/display/AutomaticBrightnessController.java +77 −30 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.display; import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; import static com.android.internal.display.BrightnessUtils.convertLinearToGamma; import static com.android.server.display.BrightnessMappingStrategy.INVALID_LUX; import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString; Loading Loading @@ -57,6 +58,7 @@ import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.os.BackgroundThread; import com.android.server.EventLogTags; import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.brightness.BrightnessUtils; import com.android.server.display.brightness.clamper.BrightnessClamperController; import com.android.server.display.config.HysteresisLevels; import com.android.server.display.feature.DisplayManagerFlags; Loading Loading @@ -112,6 +114,11 @@ public class AutomaticBrightnessController { private static final int MSG_RUN_UPDATE = 6; private static final int MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL = 7; // If our traditional math determines that the brightness is too small to actually change, // then also check if brightness percent would change at least the amount of this value, // and if so, move forward with the change. In 0-100 percent scale. private static final float MINIMUM_BRIGHTNESS_PERCENT_CHANGE = .4f; // Callbacks for requesting updates to the display's power state private final Callbacks mCallbacks; Loading Loading @@ -1009,13 +1016,31 @@ public class AutomaticBrightnessController { } return; } if (!BrightnessSynchronizer.floatEquals(mScreenAutoBrightness, newScreenAutoBrightness)) { // Return early if the brightness didn't actually change. if (BrightnessSynchronizer.floatEquals(mScreenAutoBrightness, newScreenAutoBrightness)) { // Because brightness itself is in a logarithmic scale, the values at the low end // are so low that the difference between 0% and 2% might be within the float comparison // EPSILON value. To combat this, we do a secondary check on the percent change in // brightness. final float oldPercent = getBrightnessAsPercent(mScreenAutoBrightness); final float newPercent = getBrightnessAsPercent(newScreenAutoBrightness); final boolean isBrightnessPercentDifferent = !Float.isNaN(oldPercent) && !Float.isNaN(newPercent) && (Math.abs(oldPercent - newPercent) > MINIMUM_BRIGHTNESS_PERCENT_CHANGE); if (!isBrightnessPercentDifferent) { // Brightness percent didn't change either, so lets return early here. return; } } if (mLoggingEnabled) { Slog.d(TAG, "updateAutoBrightness: " + "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " + "newScreenAutoBrightness=" + newScreenAutoBrightness); } if (!withinThreshold) { mPreThresholdBrightness = mScreenAutoBrightness; } Loading @@ -1039,14 +1064,36 @@ public class AutomaticBrightnessController { mCallbacks.updateBrightness(); } } /** * @return specified brightness value as a [0-100] percent taking current * min/max constraints into account. */ private float getBrightnessAsPercent(float brightness) { if (!BrightnessUtils.isValidBrightnessValue(brightness)) { return PowerManager.BRIGHTNESS_INVALID_FLOAT; } return 100.0f * convertLinearToGamma(MathUtils.constrainedMap( mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum, getMinBrightness(), getMaxBrightness(), brightness)); } // Clamps values with float range [0.0-1.0] private float clampScreenBrightness(float value) { final float minBrightness = mBrightnessRangeController.getCurrentBrightnessMin(); final float maxBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMax(), return MathUtils.constrain(value, getMinBrightness(), getMaxBrightness()); } private float getMinBrightness() { return Math.max(mBrightnessRangeController.getCurrentBrightnessMin(), mBrightnessClamperController.getMinBrightness()); } private float getMaxBrightness() { return Math.min(mBrightnessRangeController.getCurrentBrightnessMax(), mBrightnessClamperController.getMaxBrightness()); return MathUtils.constrain(value, minBrightness, maxBrightness); } private void prepareBrightnessAdjustmentSample() { Loading
services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java +8 −1 Original line number Diff line number Diff line Loading @@ -219,6 +219,10 @@ public class BrightnessClamperController { return mModifiersAggregatedState.mMaxBrightness; } public float getMinBrightness() { return mModifiersAggregatedState.mMinBrightness; } public boolean isThrottled() { return mModifiersAggregatedState.mMaxBrightnessReason != BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; Loading Loading @@ -246,7 +250,9 @@ public class BrightnessClamperController { || state1.mHdrRatioScaleFactor != state2.mHdrRatioScaleFactor || state1.mMaxBrightnessReason != state2.mMaxBrightnessReason || !BrightnessSynchronizer.floatEquals(state1.mMaxBrightness, state2.mMaxBrightness); state2.mMaxBrightness) || !BrightnessSynchronizer.floatEquals(state1.mMinBrightness, state2.mMinBrightness); } private void start() { Loading Loading @@ -484,5 +490,6 @@ public class BrightnessClamperController { @BrightnessInfo.BrightnessMaxReason int mMaxBrightnessReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE; float mMaxBrightness = PowerManager.BRIGHTNESS_MAX; float mMinBrightness = PowerManager.BRIGHTNESS_MIN; } }
services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java +11 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,8 @@ import java.io.PrintWriter; * lux conditions and user preferred minimum. */ public class BrightnessLowLuxModifier extends BrightnessModifier implements BrightnessClamperController.UserSwitchListener { BrightnessClamperController.UserSwitchListener, BrightnessClamperController.StatefulModifier { // To enable these logs, run: // 'adb shell setprop persist.log.tag.BrightnessLowLuxModifier DEBUG && adb reboot' Loading Loading @@ -155,7 +156,8 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements @Override public void apply(DisplayManagerInternal.DisplayPowerRequest request, DisplayBrightnessState.Builder stateBuilder) { stateBuilder.setMinBrightness(mBrightnessLowerBound); float minBrightness = Math.max(stateBuilder.getMinBrightness(), mBrightnessLowerBound); stateBuilder.setMinBrightness(minBrightness); float boundedBrightness = Math.max(mBrightnessLowerBound, stateBuilder.getBrightness()); stateBuilder.setBrightness(boundedBrightness); if (BrightnessSynchronizer.floatEquals(stateBuilder.getBrightness(), Loading @@ -164,6 +166,13 @@ public class BrightnessLowLuxModifier extends BrightnessModifier implements } } @Override public void applyStateChange(BrightnessClamperController.ModifiersAggregatedState state) { if (state.mMinBrightness < mBrightnessLowerBound) { state.mMinBrightness = mBrightnessLowerBound; } } @Override public void stop() { } Loading
services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +74 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.os.Handler; import android.os.PowerManager; import android.os.SystemClock; import android.os.test.TestLooper; import android.util.MathUtils; import android.util.SparseArray; import android.view.Display; Loading @@ -55,6 +56,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.display.BrightnessUtils; import com.android.server.display.brightness.clamper.BrightnessClamperController; import com.android.server.display.config.HysteresisLevels; import com.android.server.display.feature.DisplayManagerFlags; Loading Loading @@ -798,6 +800,78 @@ public class AutomaticBrightnessControllerTest { assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getRawAutomaticScreenBrightness(), 0.0f); } /** * Tests that movement from 1% brightness to 0% brightness is possible. * Because of gamma conversion, the difference in float brightness between 0 and 1 * percent is very small and this ensures that our float-comparison (using EPSILON) * can tell the difference between the two small values. */ @Test public void testBrightnessChangeAtLowEnd() throws Exception { ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); SensorEventListener listener = listenerCaptor.getValue(); // Min and Max brightness may be reduced due to conditions such as ambient environment, // thermal, etc. So, lets further reduce the range of the brightness values since that // can also affect the floating-point comparison resolution. float minBrightness = 0.01f; float maxBrightness = 0.25f; when(mBrightnessRangeController.getCurrentBrightnessMax()).thenReturn(maxBrightness); when(mBrightnessRangeController.getCurrentBrightnessMin()).thenReturn(minBrightness); float twoPercentLux = 40; float twoPercent = 0.02f; float twoPercentLinearBrightness = MathUtils.lerp(minBrightness, maxBrightness, BrightnessUtils.convertGammaToLinear(twoPercent)); when(mBrightnessMappingStrategy.getBrightness(eq(twoPercentLux), eq(null), anyInt())) .thenReturn(twoPercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) twoPercentLux)); assertEquals(twoPercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(twoPercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); float onePercentLux = 20; float onePercent = 0.01f; float onePercentLinearBrightness = MathUtils.lerp(minBrightness, maxBrightness, BrightnessUtils.convertGammaToLinear(onePercent)); when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) .thenReturn(onePercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) onePercentLux)); assertEquals(onePercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(onePercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); // Make a small change down an ensure the brightness actually changes. float zeroPercentLux = 2; float zeroPercent = 0.00f; float zeroPercentLinearBrightness = MathUtils.lerp(minBrightness, maxBrightness, BrightnessUtils.convertGammaToLinear(zeroPercent)); when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) .thenReturn(zeroPercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) zeroPercentLux)); assertEquals(zeroPercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(zeroPercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); // And for good measure, lets put it back to 1% when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) .thenReturn(onePercentLinearBrightness); listener.onSensorChanged(createSensorEvent(mLightSensor, (int) onePercentLux)); assertEquals(onePercentLinearBrightness, mController.getAutomaticScreenBrightness(), 0.0f); assertEquals(onePercentLinearBrightness, mController.getRawAutomaticScreenBrightness(), 0.0f); } @Test public void testGetSensorReadings() throws Exception { ArgumentCaptor<SensorEventListener> listenerCaptor = Loading