diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8a77fc94a48a5..479ba1ec2cd1d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1178,6 +1178,38 @@
+
+ false
+
+
+
+
+
+
+
+
+
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7f093827204bc..92d987edbf7dd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1648,6 +1648,8 @@
+
+
@@ -1665,6 +1667,7 @@
+
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index a3febd63e2ed9..935fa13adb47e 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -109,8 +109,8 @@ class AutomaticBrightnessController {
// weighting values positive.
private final int mWeightingIntercept;
- // accessor object for determining thresholds to change brightness dynamically
- private final HysteresisLevels mDynamicHysteresis;
+ // accessor object for determining lux levels
+ private final LuxLevels mLuxLevels;
// Amount of time to delay auto-brightness after screen on while waiting for
// the light sensor to warm-up in milliseconds.
@@ -172,6 +172,9 @@ class AutomaticBrightnessController {
// Are we going to adjust brightness while dozing.
private boolean mDozing;
+ // True if we are collecting one last light sample when dozing to set the screen brightness
+ private boolean mActiveDozeLightSensor = false;
+
// True if we are collecting a brightness adjustment sample, along with some data
// for the initial state of the sample.
private boolean mBrightnessAdjustmentSamplePending;
@@ -188,7 +191,7 @@ class AutomaticBrightnessController {
int lightSensorRate, long brighteningLightDebounceConfig,
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
- HysteresisLevels dynamicHysteresis) {
+ LuxLevels luxLevels) {
mCallbacks = callbacks;
mTwilight = LocalServices.getService(TwilightManager.class);
mSensorManager = sensorManager;
@@ -204,7 +207,7 @@ class AutomaticBrightnessController {
mAmbientLightHorizon = ambientLightHorizon;
mWeightingIntercept = ambientLightHorizon;
mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
- mDynamicHysteresis = dynamicHysteresis;
+ mLuxLevels = luxLevels;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer =
@@ -218,7 +221,7 @@ class AutomaticBrightnessController {
}
public int getAutomaticScreenBrightness() {
- if (mDozing) {
+ if (mDozing && !mLuxLevels.hasDynamicDozeBrightness()) {
return (int) (mScreenAutoBrightness * mDozeScaleFactor);
}
return mScreenAutoBrightness;
@@ -232,13 +235,26 @@ class AutomaticBrightnessController {
// and hold onto the last computed screen auto brightness. We save the dozing flag for
// debugging purposes.
mDozing = dozing;
- boolean changed = setLightSensorEnabled(enable && !dozing);
+ boolean enableSensor = enable && !dozing;
+ if (enableSensor && !mLightSensorEnabled && mActiveDozeLightSensor) {
+ mActiveDozeLightSensor = false;
+ } else if (!enableSensor && mLightSensorEnabled && mLuxLevels.hasDynamicDozeBrightness()) {
+ // keep the light sensor active until another light sample is taken in doze mode
+ mActiveDozeLightSensor = true;
+ if (mLuxLevels.useNewSensorSamplesForDoze()) {
+ mAmbientLightRingBuffer.clear();
+ mInitialHorizonAmbientLightRingBuffer.clear();
+ mAmbientLuxValid = false;
+ return;
+ }
+ }
+ boolean changed = setLightSensorEnabled(enableSensor);
changed |= setScreenAutoBrightnessAdjustment(adjustment);
changed |= setUseTwilight(useTwilight);
if (changed) {
updateAutoBrightness(false /*sendUpdate*/);
}
- if (enable && !dozing && userInitiatedChange) {
+ if (enableSensor && userInitiatedChange) {
prepareBrightnessAdjustmentSample();
}
}
@@ -292,6 +308,9 @@ class AutomaticBrightnessController {
if (enable) {
if (!mLightSensorEnabled) {
mLightSensorEnabled = true;
+ mAmbientLightRingBuffer.clear();
+ mInitialHorizonAmbientLightRingBuffer.clear();
+ mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
mLightSensorEnableTime = SystemClock.uptimeMillis();
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
mLightSensorRate * 1000, mHandler);
@@ -300,11 +319,9 @@ class AutomaticBrightnessController {
} else {
if (mLightSensorEnabled) {
mLightSensorEnabled = false;
- mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
mRecentLightSamples = 0;
- mAmbientLightRingBuffer.clear();
- mInitialHorizonAmbientLightRingBuffer.clear();
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
+ Slog.d(TAG, "disabling light sensor");
mSensorManager.unregisterListener(mLightSensorListener);
}
}
@@ -316,6 +333,11 @@ class AutomaticBrightnessController {
applyLightSensorMeasurement(time, lux);
updateAmbientLux(time);
+ if (mActiveDozeLightSensor) {
+ // disable the ambient light sensor and update the screen brightness
+ setLightSensorEnabled(false);
+ updateAutoBrightness(true /*sendUpdate*/);
+ }
}
private void applyLightSensorMeasurement(long time, float lux) {
@@ -327,6 +349,7 @@ class AutomaticBrightnessController {
}
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
+ Slog.d(TAG, "pushing lux: " + lux);
// Remember this sample value.
mLastObservedLux = lux;
@@ -343,8 +366,8 @@ class AutomaticBrightnessController {
private void setAmbientLux(float lux) {
mAmbientLux = lux;
- mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
- mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
+ mBrighteningLuxThreshold = mLuxLevels.getBrighteningThreshold(lux);
+ mDarkeningLuxThreshold = mLuxLevels.getDarkeningThreshold(lux);
}
private float calculateAmbientLux(long now) {
@@ -516,8 +539,14 @@ class AutomaticBrightnessController {
}
}
- int newScreenAutoBrightness =
+ int newScreenAutoBrightness;
+ if (mActiveDozeLightSensor) {
+ newScreenAutoBrightness = mLuxLevels.getDozeBrightness(mAmbientLux);
+ } else {
+ newScreenAutoBrightness =
clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
+ }
+
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index df5def9ad9b90..dfd42543c0783 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -322,15 +322,6 @@ 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);
@@ -342,6 +333,24 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
+ // hysteresis configs
+ int[] brightHysteresisLevels = resources.getIntArray(
+ com.android.internal.R.array.config_dynamicHysteresisBrightLevels);
+ int[] darkHysteresisLevels = resources.getIntArray(
+ com.android.internal.R.array.config_dynamicHysteresisDarkLevels);
+ int[] luxHysteresisLevels = resources.getIntArray(
+ com.android.internal.R.array.config_dynamicHysteresisLuxLevels);
+ // doze brightness configs
+ int[] dozeSensorLuxLevels = resources.getIntArray(
+ com.android.internal.R.array.config_dozeSensorLuxLevels);
+ int[] dozeBrightnessBacklightValues = resources.getIntArray(
+ com.android.internal.R.array.config_dozeBrightnessBacklightValues);
+ boolean useNewSensorSamplesForDoze = resources.getBoolean(
+ com.android.internal.R.bool.config_useNewSensorSamplesForDoze);
+ LuxLevels luxLevels = new LuxLevels(brightHysteresisLevels, darkHysteresisLevels,
+ luxHysteresisLevels, useNewSensorSamplesForDoze, dozeSensorLuxLevels,
+ dozeBrightnessBacklightValues);
+
Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
if (screenAutoBrightnessSpline == null) {
Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues "
@@ -368,7 +377,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
- autoBrightnessAdjustmentMaxGamma, dynamicHysteresis);
+ autoBrightnessAdjustmentMaxGamma, luxLevels);
}
}
diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java
deleted file mode 100644
index b062225638118..0000000000000
--- a/services/core/java/com/android/server/display/HysteresisLevels.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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;
- }
-}
diff --git a/services/core/java/com/android/server/display/LuxLevels.java b/services/core/java/com/android/server/display/LuxLevels.java
new file mode 100644
index 0000000000000..a13626d8f820c
--- /dev/null
+++ b/services/core/java/com/android/server/display/LuxLevels.java
@@ -0,0 +1,145 @@
+/*
+ * 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 level values.
+ */
+final class LuxLevels {
+ private static final String TAG = "LuxLevels";
+
+ private static final boolean DEBUG = true;
+
+ private final boolean mUseNewSensorSamplesForDoze;
+
+ private final float[] mBrightLevels;
+ private final float[] mDarkLevels;
+ private final float[] mLuxHysteresisLevels;
+ private final float[] mDozeBacklightLevels;
+ private final float[] mDozeSensorLuxLevels;
+
+ /**
+ * Creates a {@code LuxLevels} object with the given integer arrays. The following arrays
+ * are either empty or have the following relations:
+ * {@code brightLevels} and {@code darkLevels} have the same length n.
+ * {@code luxLevels} has length n+1.
+ *
+ * {@code dozeSensorLuxLevels} has length r.
+ * {@code dozeBacklightLevels} has length r+1.
+ *
+ * @param brightLevels an array of brightening hysteresis constraint constants
+ * @param darkLevels an array of darkening hysteresis constraint constants
+ * @param luxHysteresisLevels a monotonically increasing array of illuminance thresholds in lux
+ * @param dozeSensorLuxLevels a monotonically increasing array of ALS thresholds in lux
+ * @param dozeBacklightLevels an array of screen brightness values for doze mode in lux
+ */
+ public LuxLevels(int[] brightLevels, int[] darkLevels, int[] luxHysteresisLevels,
+ boolean useNewSensorSamplesForDoze, int[] dozeSensorLuxLevels,
+ int[] dozeBacklightLevels) {
+ if (brightLevels.length != darkLevels.length ||
+ darkLevels.length !=luxHysteresisLevels.length + 1) {
+ throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
+ }
+ if (dozeBacklightLevels.length > 0 && dozeSensorLuxLevels.length > 0
+ && dozeBacklightLevels.length != dozeSensorLuxLevels.length + 1) {
+ throw new IllegalArgumentException("Mismatch between doze lux array lengths.");
+ }
+ mBrightLevels = setArrayFormat(brightLevels, 1000.0f);
+ mDarkLevels = setArrayFormat(darkLevels, 1000.0f);
+ mLuxHysteresisLevels = setArrayFormat(luxHysteresisLevels, 1.0f);
+ mUseNewSensorSamplesForDoze = useNewSensorSamplesForDoze;
+ mDozeSensorLuxLevels = setArrayFormat(dozeSensorLuxLevels, 1.0f);
+ mDozeBacklightLevels = setArrayFormat(dozeBacklightLevels, 1.0f);
+ }
+
+ /**
+ * Return the brightening hysteresis threshold for the given lux level.
+ */
+ public float getBrighteningThreshold(float lux) {
+ float brightConstant = getReferenceLevel(lux, mBrightLevels, mLuxHysteresisLevels);
+ 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, mLuxHysteresisLevels);
+ float darkThreshold = lux * (1.0f - darkConstant);
+ if (DEBUG) {
+ Slog.d(TAG, "dark hysteresis constant= " + darkConstant + ", threshold="
+ + darkThreshold + ", lux=" + lux);
+ }
+ return darkThreshold;
+ }
+
+ /**
+ * Return the doze backlight brightness level for the given ambient sensor lux level.
+ */
+ public int getDozeBrightness(float lux) {
+ int dozeBrightness = (int) getReferenceLevel(lux, mDozeBacklightLevels,
+ mDozeSensorLuxLevels);
+ if (DEBUG) {
+ Slog.d(TAG, "doze brightness: " + dozeBrightness + ", lux=" + lux);
+ }
+ return dozeBrightness;
+ }
+
+ /**
+ * Find the index of the closest value in {@code thresholdLevels} to {@code lux} and return
+ * the {@code referenceLevels} entry with that index.
+ */
+ private float getReferenceLevel(float lux, float[] referenceLevels, float[] thresholdLevels) {
+ int index = 0;
+ while (thresholdLevels.length > index && lux >= thresholdLevels[index]) {
+ ++index;
+ }
+ return referenceLevels[index];
+ }
+
+ /**
+ * Return if the doze backlight brightness level is specified dynamically.
+ */
+ public boolean hasDynamicDozeBrightness() {
+ return mDozeSensorLuxLevels.length > 0;
+ }
+
+ /**
+ * Return if new ALS samples should be used for determining screen brightness while dozing.
+ */
+ public boolean useNewSensorSamplesForDoze() {
+ return mUseNewSensorSamplesForDoze;
+ }
+
+ /**
+ * 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;
+ }
+}