diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 89dcdc3281278..ecbc5b50da7b9 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1132,6 +1132,40 @@ + + + 100 + + + + + 200 + + + + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 22665b28cd5a7..87d3eb43d51bb 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1639,6 +1639,9 @@ + + + diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 15ae846186fa9..a3febd63e2ed9 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -50,13 +50,7 @@ class AutomaticBrightnessController { // If true, enables the use of the screen auto-brightness adjustment setting. private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true; - // 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; - - // How long the current sensor reading is assumed to be valid beyond the current time. + // How long the current sensor reading is assumed to be valid beyond the current time. // This provides a bit of prediction, as well as ensures that the weight for the last sample is // non-zero, which in turn ensures that the total weight is non-zero. private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100; @@ -71,7 +65,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. @@ -115,6 +109,9 @@ class AutomaticBrightnessController { // weighting values positive. private final int mWeightingIntercept; + // 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. @@ -190,7 +187,8 @@ class AutomaticBrightnessController { int brightnessMin, int brightnessMax, float dozeScaleFactor, int lightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, - int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma ) { + int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma, + HysteresisLevels dynamicHysteresis) { mCallbacks = callbacks; mTwilight = LocalServices.getService(TwilightManager.class); mSensorManager = sensorManager; @@ -206,6 +204,7 @@ class AutomaticBrightnessController { mAmbientLightHorizon = ambientLightHorizon; mWeightingIntercept = ambientLightHorizon; mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma; + mDynamicHysteresis = dynamicHysteresis; mHandler = new AutomaticBrightnessHandler(looper); mAmbientLightRingBuffer = @@ -344,8 +343,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 d6cc9fc6a85cd..df5def9ad9b90 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. @@ -322,6 +322,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma, 1, 1); + 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); @@ -358,8 +367,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate, brighteningLightDebounce, darkeningLightDebounce, - autoBrightnessResetAmbientLuxAfterWarmUp, - ambientLightHorizon, autoBrightnessAdjustmentMaxGamma); + autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon, + autoBrightnessAdjustmentMaxGamma, 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; + } +}