From 3275a3a5a54b6e3148db23609d1b3d35e9277bc0 Mon Sep 17 00:00:00 2001 From: Julius D'souza Date: Sun, 7 Aug 2016 19:08:30 -0700 Subject: [PATCH] DO NOT MERGE ANYWHERE: Add dynamic illuminance hysteresis support Bug: 18572096 Change-Id: Ie0ff1990b8f4a3d435328834871f04a6e2bd5e97 --- core/res/res/values/config.xml | 34 ++++++ core/res/res/values/symbols.xml | 3 + .../AutomaticBrightnessController.java | 19 ++-- .../display/DisplayPowerController.java | 13 ++- .../server/display/HysteresisLevels.java | 104 ++++++++++++++++++ 5 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 services/core/java/com/android/server/display/HysteresisLevels.java diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f745b52c5f4ce..b2d53c3fa2e4e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1082,6 +1082,40 @@ + + + 100 + + + + + 200 + + + + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4fcc1d3286054..89823a36bd408 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1607,6 +1607,9 @@ + + + diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index e15bca6ca7a18..d9444a54e0b1f 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -56,12 +56,6 @@ class AutomaticBrightnessController { // Period of time in which to consider light samples in milliseconds. private static final int AMBIENT_LIGHT_HORIZON = 10000; - // Hysteresis constraints for brightening or darkening. - // The recent lux must have changed by at least this fraction relative to the - // current ambient lux before a change will be considered. - private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f; - private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f; - // The intercept used for the weighting calculation. This is used in order to keep all possible // weighting values positive. private static final int WEIGHTING_INTERCEPT = AMBIENT_LIGHT_HORIZON; @@ -95,7 +89,7 @@ class AutomaticBrightnessController { private static final int MSG_UPDATE_AMBIENT_LUX = 1; private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2; - // Callbacks for requesting updates to the the display's power state + // Callbacks for requesting updates to the display's power state private final Callbacks mCallbacks; // The sensor manager. @@ -132,6 +126,9 @@ class AutomaticBrightnessController { // and only then decide whether to change brightness. private final boolean mResetAmbientLuxAfterWarmUpConfig; + // accessor object for determining thresholds to change brightness dynamically + private final HysteresisLevels mDynamicHysteresis; + // Amount of time to delay auto-brightness after screen on while waiting for // the light sensor to warm-up in milliseconds. // May be 0 if no warm-up is required. @@ -197,7 +194,8 @@ class AutomaticBrightnessController { SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor, int lightSensorRate, long brighteningLightDebounceConfig, - long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig) { + long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, + HysteresisLevels dynamicHysteresis) { mCallbacks = callbacks; mTwilight = LocalServices.getService(TwilightManager.class); mSensorManager = sensorManager; @@ -210,6 +208,7 @@ class AutomaticBrightnessController { mBrighteningLightDebounceConfig = brighteningLightDebounceConfig; mDarkeningLightDebounceConfig = darkeningLightDebounceConfig; mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig; + mDynamicHysteresis = dynamicHysteresis; mHandler = new AutomaticBrightnessHandler(looper); mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate); @@ -327,8 +326,8 @@ class AutomaticBrightnessController { private void setAmbientLux(float lux) { mAmbientLux = lux; - mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS); - mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS); + mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux); + mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux); } private float calculateAmbientLux(long now) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 78fa34309539e..3f0b8b0771c0d 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -72,7 +72,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final String TAG = "DisplayPowerController"; private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked"; - private static boolean DEBUG = false; + private static final boolean DEBUG = false; private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false; // If true, uses the color fade on animation. @@ -317,6 +317,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean( com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp); + int[] brightLevels = resources.getIntArray( + com.android.internal.R.array.config_dynamicHysteresisBrightLevels); + int[] darkLevels = resources.getIntArray( + com.android.internal.R.array.config_dynamicHysteresisDarkLevels); + int[] luxLevels = resources.getIntArray( + com.android.internal.R.array.config_dynamicHysteresisLuxLevels); + HysteresisLevels dynamicHysteresis = new HysteresisLevels( + brightLevels, darkLevels, luxLevels); + if (mUseSoftwareAutoBrightnessConfig) { int[] lux = resources.getIntArray( com.android.internal.R.array.config_autoBrightnessLevels); @@ -353,7 +362,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate, brighteningLightDebounce, darkeningLightDebounce, - autoBrightnessResetAmbientLuxAfterWarmUp); + autoBrightnessResetAmbientLuxAfterWarmUp, dynamicHysteresis); } } diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java new file mode 100644 index 0000000000000..b062225638118 --- /dev/null +++ b/services/core/java/com/android/server/display/HysteresisLevels.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 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.server.display; + +import android.util.Slog; + +/** + * A helper class for handling access to illuminance hysteresis level values. + */ +final class HysteresisLevels { + private static final String TAG = "HysteresisLevels"; + + // Default hysteresis constraints for brightening or darkening. + // The recent lux must have changed by at least this fraction relative to the + // current ambient lux before a change will be considered. + private static final float DEFAULT_BRIGHTENING_HYSTERESIS = 0.10f; + private static final float DEFAULT_DARKENING_HYSTERESIS = 0.20f; + + private static final boolean DEBUG = false; + + private final float[] mBrightLevels; + private final float[] mDarkLevels; + private final float[] mLuxLevels; + + /** + * Creates a {@code HysteresisLevels} object with the given equal-length + * integer arrays. + * @param brightLevels an array of brightening hysteresis constraint constants + * @param darkLevels an array of darkening hysteresis constraint constants + * @param luxLevels a monotonically increasing array of illuminance + * thresholds in units of lux + */ + public HysteresisLevels(int[] brightLevels, int[] darkLevels, int[] luxLevels) { + if (brightLevels.length != darkLevels.length || darkLevels.length != luxLevels.length + 1) { + throw new IllegalArgumentException("Mismatch between hysteresis array lengths."); + } + mBrightLevels = setArrayFormat(brightLevels, 1000.0f); + mDarkLevels = setArrayFormat(darkLevels, 1000.0f); + mLuxLevels = setArrayFormat(luxLevels, 1.0f); + } + + /** + * Return the brightening hysteresis threshold for the given lux level. + */ + public float getBrighteningThreshold(float lux) { + float brightConstant = getReferenceLevel(lux, mBrightLevels); + float brightThreshold = lux * (1.0f + brightConstant); + if (DEBUG) { + Slog.d(TAG, "bright hysteresis constant=: " + brightConstant + ", threshold=" + + brightThreshold + ", lux=" + lux); + } + return brightThreshold; + } + + /** + * Return the darkening hysteresis threshold for the given lux level. + */ + public float getDarkeningThreshold(float lux) { + float darkConstant = getReferenceLevel(lux, mDarkLevels); + float darkThreshold = lux * (1.0f - darkConstant); + if (DEBUG) { + Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold=" + + darkThreshold + ", lux=" + lux); + } + return darkThreshold; + } + + /** + * Return the hysteresis constant for the closest lux threshold value to the + * current illuminance from the given array. + */ + private float getReferenceLevel(float lux, float[] referenceLevels) { + int index = 0; + while (mLuxLevels.length > index && lux >= mLuxLevels[index]) { + ++index; + } + return referenceLevels[index]; + } + + /** + * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}. + */ + private float[] setArrayFormat(int[] configArray, float divideFactor) { + float[] levelArray = new float[configArray.length]; + for (int index = 0; levelArray.length > index; ++index) { + levelArray[index] = (float)configArray[index] / divideFactor; + } + return levelArray; + } +}