diff options
6 files changed, 241 insertions, 127 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8a77fc94a48a..479ba1ec2cd1 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 7f093827204b..92d987edbf7d 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 a3febd63e2ed..935fa13adb47 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 df5def9ad9b9..dfd42543c078 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 b06222563811..000000000000 --- 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 000000000000..a13626d8f820 --- /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; + } +} |