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;
+ }
+}