diff options
3 files changed, 158 insertions, 82 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/BrightnessUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/BrightnessUtils.java new file mode 100644 index 000000000000..55723f9d8ed4 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/display/BrightnessUtils.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.display; + +import android.util.MathUtils; + +public class BrightnessUtils { + + public static final int GAMMA_SPACE_MAX = 1023; + + // Hybrid Log Gamma constant values + private static final float R = 0.5f; + private static final float A = 0.17883277f; + private static final float B = 0.28466892f; + private static final float C = 0.55991073f; + + /** + * A function for converting from the gamma space that the slider works in to the + * linear space that the setting works in. + * + * The gamma space effectively provides us a way to make linear changes to the slider that + * result in linear changes in perception. If we made changes to the slider in the linear space + * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law). + * + * Internally, this implements the Hybrid Log Gamma electro-optical transfer function, which is + * a slight improvement to the typical gamma transfer function for displays whose max + * brightness exceeds the 120 nit reference point, but doesn't set a specific reference + * brightness like the PQ function does. + * + * Note that this transfer function is only valid if the display's backlight value is a linear + * control. If it's calibrated to be something non-linear, then a different transfer function + * should be used. + * + * @param val The slider value. + * @param min The minimum acceptable value for the setting. + * @param max The maximum acceptable value for the setting. + * @return The corresponding setting value. + */ + public static final int convertGammaToLinear(int val, int min, int max) { + final float normalizedVal = MathUtils.norm(0, GAMMA_SPACE_MAX, val); + final float ret; + if (normalizedVal <= R) { + ret = MathUtils.sq(normalizedVal / R); + } else { + ret = MathUtils.exp((normalizedVal - C) / A) + B; + } + + // HLG is normalized to the range [0, 12], so we need to re-normalize to the range [0, 1] + // in order to derive the correct setting value. + return Math.round(MathUtils.lerp(min, max, ret / 12)); + } + + /** + * A function for converting from the linear space that the setting works in to the + * gamma space that the slider works in. + * + * The gamma space effectively provides us a way to make linear changes to the slider that + * result in linear changes in perception. If we made changes to the slider in the linear space + * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law). + * + * Internally, this implements the Hybrid Log Gamma opto-electronic transfer function, which is + * a slight improvement to the typical gamma transfer function for displays whose max + * brightness exceeds the 120 nit reference point, but doesn't set a specific reference + * brightness like the PQ function does. + * + * Note that this transfer function is only valid if the display's backlight value is a linear + * control. If it's calibrated to be something non-linear, then a different transfer function + * should be used. + * + * @param val The brightness setting value. + * @param min The minimum acceptable value for the setting. + * @param max The maximum acceptable value for the setting. + * @return The corresponding slider value + */ + public static final int convertLinearToGamma(int val, int min, int max) { + // For some reason, HLG normalizes to the range [0, 12] rather than [0, 1] + final float normalizedVal = MathUtils.norm(min, max, val) * 12; + final float ret; + if (normalizedVal <= 1f) { + ret = MathUtils.sqrt(normalizedVal) * R; + } else { + ret = A * MathUtils.log(normalizedVal - B) + C; + } + + return Math.round(MathUtils.lerp(0, GAMMA_SPACE_MAX, ret)); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java new file mode 100644 index 000000000000..eb7ad6d919cf --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.display; + +import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX; +import static com.google.common.truth.Truth.assertThat; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class BrightnessUtilsTest { + + private static final int MIN = 1; + private static final int MAX = 255; + + @Test + public void linearToGamma_minValue_shouldReturn0() { + assertThat(BrightnessUtils.convertLinearToGamma(MIN, MIN, MAX)).isEqualTo(0); + } + + @Test + public void linearToGamma_maxValue_shouldReturnGammaSpaceMax() { + assertThat(BrightnessUtils.convertLinearToGamma(MAX, MIN, MAX)).isEqualTo(GAMMA_SPACE_MAX); + } + + @Test + public void gammaToLinear_minValue_shouldReturnMin() { + assertThat(BrightnessUtils.convertGammaToLinear(MIN, MIN, MAX)).isEqualTo(MIN); + } + + @Test + public void gammaToLinear_gammaSpaceValue_shouldReturnMax() { + assertThat(BrightnessUtils.convertGammaToLinear(GAMMA_SPACE_MAX, MIN, MAX)).isEqualTo(MAX); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 1736f386a3b3..be0aa117b9b4 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -16,6 +16,10 @@ package com.android.systemui.settings; +import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX; +import static com.android.settingslib.display.BrightnessUtils.convertGammaToLinear; +import static com.android.settingslib.display.BrightnessUtils.convertLinearToGamma; + import android.animation.ValueAnimator; import android.content.ContentResolver; import android.content.Context; @@ -24,7 +28,6 @@ import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; -import android.os.IPowerManager; import android.os.Looper; import android.os.Message; import android.os.PowerManager; @@ -36,7 +39,6 @@ import android.provider.Settings; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; import android.util.Log; -import android.util.MathUtils; import android.widget.ImageView; import com.android.internal.logging.MetricsLogger; @@ -50,15 +52,8 @@ public class BrightnessController implements ToggleSlider.Listener { private static final String TAG = "StatusBar.BrightnessController"; private static final boolean SHOW_AUTOMATIC_ICON = false; - private static final int SLIDER_MAX = 1023; private static final int SLIDER_ANIMATION_DURATION = 3000; - // Hybrid Log Gamma constant values - private static final float R = 0.5f; - private static final float A = 0.17883277f; - private static final float B = 0.28466892f; - private static final float C = 0.55991073f; - private static final int MSG_UPDATE_ICON = 0; private static final int MSG_UPDATE_SLIDER = 1; private static final int MSG_SET_CHECKED = 2; @@ -273,7 +268,7 @@ public class BrightnessController implements ToggleSlider.Listener { mContext = context; mIcon = icon; mControl = control; - mControl.setMax(SLIDER_MAX); + mControl.setMax(GAMMA_SPACE_MAX); mBackgroundHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER)); mUserTracker = new CurrentUserTracker(mContext) { @Override @@ -481,76 +476,4 @@ public class BrightnessController implements ToggleSlider.Listener { mSliderAnimator.start(); } - /** - * A function for converting from the linear space that the setting works in to the - * gamma space that the slider works in. - * - * The gamma space effectively provides us a way to make linear changes to the slider that - * result in linear changes in perception. If we made changes to the slider in the linear space - * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law). - * - * Internally, this implements the Hybrid Log Gamma opto-electronic transfer function, which is - * a slight improvement to the typical gamma transfer function for displays whose max - * brightness exceeds the 120 nit reference point, but doesn't set a specific reference - * brightness like the PQ function does. - * - * Note that this transfer function is only valid if the display's backlight value is a linear - * control. If it's calibrated to be something non-linear, then a different transfer function - * should be used. - * - * @param val The brightness setting value. - * @param min The minimum acceptable value for the setting. - * @param max The maximum acceptable value for the setting. - * - * @return The corresponding slider value - */ - private static final int convertLinearToGamma(int val, int min, int max) { - // For some reason, HLG normalizes to the range [0, 12] rather than [0, 1] - final float normalizedVal = MathUtils.norm(min, max, val) * 12; - final float ret; - if (normalizedVal <= 1f) { - ret = MathUtils.sqrt(normalizedVal) * R; - } else { - ret = A * MathUtils.log(normalizedVal - B) + C; - } - - return Math.round(MathUtils.lerp(0, SLIDER_MAX, ret)); - } - - /** - * A function for converting from the gamma space that the slider works in to the - * linear space that the setting works in. - * - * The gamma space effectively provides us a way to make linear changes to the slider that - * result in linear changes in perception. If we made changes to the slider in the linear space - * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law). - * - * Internally, this implements the Hybrid Log Gamma electro-optical transfer function, which is - * a slight improvement to the typical gamma transfer function for displays whose max - * brightness exceeds the 120 nit reference point, but doesn't set a specific reference - * brightness like the PQ function does. - * - * Note that this transfer function is only valid if the display's backlight value is a linear - * control. If it's calibrated to be something non-linear, then a different transfer function - * should be used. - * - * @param val The slider value. - * @param min The minimum acceptable value for the setting. - * @param max The maximum acceptable value for the setting. - * - * @return The corresponding setting value. - */ - private static final int convertGammaToLinear(int val, int min, int max) { - final float normalizedVal = MathUtils.norm(0, SLIDER_MAX, val); - final float ret; - if (normalizedVal <= R) { - ret = MathUtils.sq(normalizedVal/R); - } else { - ret = MathUtils.exp((normalizedVal - C) / A) + B; - } - - // HLG is normalized to the range [0, 12], so we need to re-normalize to the range [0, 1] - // in order to derive the correct setting value. - return Math.round(MathUtils.lerp(min, max, ret / 12)); - } } |