Merge "DO NOT MERGE: Ambient light sensor changes for doze mode." into cw-f-dev
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8a77fc9..479ba1e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1178,6 +1178,38 @@
<integer-array name="config_dynamicHysteresisLuxLevels">
</integer-array>
+ <!-- This flag requires config_dozeSensorLuxLevels to have one or more entries and only affects
+ the screen brightness while dozing. The screen brightness of a device is based off of a
+ ring buffer of the last n seconds of ambient light sensor sample readings.
+
+ If this flag is true, then this buffer is cleared and the screen brightness is based off of
+ ambient light sensor readings that are obtained while the device is dozing. This mode may
+ be better suited for watches.
+
+ If this flag is false, then this buffer is untouched. -->
+ <bool name="config_useNewSensorSamplesForDoze">false</bool>
+
+ <!-- Array of ambient light sensor lux threshold values for determining screen brightness for
+ devices that have both an ambient light sensor and the screen on while dozing. This is
+ used to determine the screen brightness while dozing by calculating the index to use for
+ lookup and then setting the screen brightness value to the corresponding value of
+ config_dozeBrightnessBacklightValues.
+
+ The (zero-based) index is calculated as follows: (MAX is the largest index of the array)
+ condition calculated index
+ value < lux[0] 0
+ lux[n] <= value < lux[n+1] n+1
+ lux[MAX] <= value MAX+1 -->
+ <integer-array name="config_dozeSensorLuxLevels">
+ </integer-array>
+
+ <!-- Array of values for determining screen brightness for devices that have both an ambient
+ light sensor and the screen on while dozing. The length of this array is assumed to be one
+ greater than config_dozeModeSensorLuxLevels if they are not both empty. See the
+ config_dozeModeSensorLuxLevels description for how the backlight value is chosen. -->
+ <integer-array name="config_dozeBrightnessBacklightValues">
+ </integer-array>
+
<!-- Amount of time it takes for the light sensor to warm up in milliseconds.
For this time after the screen turns on, the Power Manager
will not debounce light sensor readings -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7f09382..92d987e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1648,6 +1648,8 @@
<java-symbol type="array" name="config_dynamicHysteresisBrightLevels" />
<java-symbol type="array" name="config_dynamicHysteresisDarkLevels" />
<java-symbol type="array" name="config_dynamicHysteresisLuxLevels" />
+ <java-symbol type="array" name="config_dozeBrightnessBacklightValues" />
+ <java-symbol type="array" name="config_dozeSensorLuxLevels" />
<java-symbol type="array" name="config_protectedNetworks" />
<java-symbol type="array" name="config_statusBarIcons" />
<java-symbol type="array" name="config_tether_bluetooth_regexs" />
@@ -1665,6 +1667,7 @@
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
<java-symbol type="array" name="config_onlySingleDcAllowed" />
+ <java-symbol type="bool" name="config_useNewSensorSamplesForDoze" />
<java-symbol type="bool" name="config_useAttentionLight" />
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index a3febd6..935fa13 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 @@
// 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 @@
// 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 @@
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 @@
mAmbientLightHorizon = ambientLightHorizon;
mWeightingIntercept = ambientLightHorizon;
mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
- mDynamicHysteresis = dynamicHysteresis;
+ mLuxLevels = luxLevels;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer =
@@ -218,7 +221,7 @@
}
public int getAutomaticScreenBrightness() {
- if (mDozing) {
+ if (mDozing && !mLuxLevels.hasDynamicDozeBrightness()) {
return (int) (mScreenAutoBrightness * mDozeScaleFactor);
}
return mScreenAutoBrightness;
@@ -232,13 +235,26 @@
// 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 @@
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 @@
} 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 @@
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 @@
}
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
+ Slog.d(TAG, "pushing lux: " + lux);
// Remember this sample value.
mLastObservedLux = lux;
@@ -343,8 +366,8 @@
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 @@
}
}
- 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 df5def9..dfd4254 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 @@
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 @@
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 @@
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 b062225..0000000
--- 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 0000000..a13626d
--- /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;
+ }
+}