自动背光在Android系统中属于display显示相关模块,具体是和Lights和Power交互比较多,Power控制其亮度,灭屏,暗屏以及自动背光设置开关等,Lights负责背光灯的背光亮度值的变化。
1、代码主要涉及到frameworks/base/services/core/java/com/android/server/display 目录下的DisplayPowerController.java、AutomaticBrightnessController.java。
2、AutomaticBrightnessController.java中的一些变量
mScreenAutoBrightness:屏幕亮度级别是由自动亮度算法决定的,实际的亮度应向这个值靠拢。我们保留这个值,即使我们停止使用光传感器,以便我们可以快速恢复到之前的自动亮度级别。如果当前没有可用的自动亮度值,设置为-1。
// The screen brightness level that has been chosen by the auto-brightness
// algorithm. The actual brightness should ramp towards this value.
// We preserve this value even when we stop using the light sensor so
// that we can quickly revert to the previous auto-brightness level
// while the light sensor warms up.
// Use -1 if there is no current auto-brightness value available.
private int mScreenAutoBrightness = -1;
mResetAmbientLuxAfterWarmUpConfig:如果设置为true,屏幕点亮后,控制器根据当前传感器读到的值调整亮度;如果是false,控制器将收集更多的数据,然后决定是否改变亮度。
// If true immediately after the screen is turned on the controller will try to adjust the
// brightness based on the current sensor reads. If false, the controller will collect more data
// and only then decide whether to change brightness.
private final boolean mResetAmbientLuxAfterWarmUpConfig;
// The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter)
private float mScreenAutoBrightnessAdjustment = 0.0f;
mAmbientLux:当前接收的环境光级别。
// The currently accepted nominal ambient light level.
private float mAmbientLux;
// A ring buffer containing all of the recent ambient light sensor readings.
private AmbientLightRingBuffer mAmbientLightRingBuffer;
// 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;
// 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.
private int mLightSensorWarmUpTimeConfig;
// Period of time in which to consider light samples in milliseconds.
private final int mAmbientLightHorizon;
// A ring buffer containing the light sensor readings for the initial horizon period.
private AmbientLightRingBuffer mInitialHorizonAmbientLightRingBuffer;
3、使用dump查看自动亮度调节的变量值
adb shell dumpsys display > e:\display.txt
4、亮度计算算法及调节
自动背光的主要控制功能是DisplayPowerController和AutomaticBrightnessController两个类结合起来工作的。DisplayPowerController属于Display模块,其控制设备屏幕亮灭、背光、与Power关系密切,这里主要看下屏幕亮度的控制这方面的逻辑。
首先,在DisplayManagerService中初始化DisplayPowerController,如下:
private final class LocalService extends DisplayManagerInternal {
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
DisplayBlanker blanker = new DisplayBlanker() {
@Override
public void requestDisplayState(int state, int brightness) {
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state, brightness);
}
callbacks.onDisplayStateChange(state);
if (state != Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state, brightness);
}
}
};
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
}
}
initPowerManagement()方法是比较重要的,这里是重写了DisplayManagerInternal中的initPowerManagement()抽象方法,该方法中有两个重要作用:一是回调到PowerManagerService中设置屏幕显示状态与power状态到底层;二是向LightService里面去设置屏幕背光。其中使用到的参数是由在PowerManagerService中调用initPowerManagement()方法传递的,如下:
// Initialize display power management.
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
我们接着看下DisplayPowerController的构造方法,如下:
/**
* Creates the display power controller.
*/
public DisplayPowerController(Context context,
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker) {
mHandler = new DisplayControllerHandler(handler.getLooper());
mCallbacks = callbacks;
mBatteryStats = BatteryStatsService.getService();
mSensorManager = sensorManager;
mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
mBlanker = blanker;
mContext = context;
final Resources resources = context.getResources();
final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum));//屏幕最小亮度值,设置过小可能会点不亮屏幕。(23)
mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze));//处于doze状态时的屏幕亮度.(1)
mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim));//屏幕变暗时的值。(23)
mScreenBrightnessDarkConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDark));//屏幕完全黑暗时的值。(23)
if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
Slog.w(TAG, "Expected config_screenBrightnessDark ("
+ mScreenBrightnessDarkConfig + ") to be less than or equal to "
+ "config_screenBrightnessDim (" + mScreenBrightnessDimConfig + ").");
}
if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
Slog.w(TAG, "Expected config_screenBrightnessDark ("
+ mScreenBrightnessDarkConfig + ") to be less than or equal to "
+ "config_screenBrightnessSettingMinimum ("
+ screenBrightnessSettingMinimum + ").");
}
int screenBrightnessRangeMinimum = Math.min(Math.min(
screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
mScreenBrightnessDarkConfig);//取三个值中的最小值
mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;//屏幕最大亮度
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);//是否支持自动亮度,false
mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);// false
mBrightnessRampRateFast = resources.getInteger(
com.android.internal.R.integer.config_brightness_ramp_rate_fast);// 亮度渐变动画速率,较快的亮度速率,200
int lightSensorRate = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessLightSensorRate);// 250
long brighteningLightDebounce = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);// 2000
long darkeningLightDebounce = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);// 4000
boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);// true
int ambientLightHorizon = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessAmbientLightHorizon);// 10000
float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
1, 1);// 300%
if (mUseSoftwareAutoBrightnessConfig) {
int[] lux = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevels);
int[] screenBrightness = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
int lightSensorWarmUpTimeConfig = resources.getInteger(
com.android.internal.R.integer.config_lightSensorWarmupTime);// 0
final float dozeScaleFactor = resources.getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);// 100%
Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
if (screenAutoBrightnessSpline == null) {
Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues "
+ "(size " + screenBrightness.length + ") "
+ "must be monotic and have exactly one more entry than "
+ "config_autoBrightnessLevels (size " + lux.length + ") "
+ "which must be strictly increasing. "
+ "Auto-brightness will be disabled.");
mUseSoftwareAutoBrightnessConfig = false;
} else {
int bottom = clampAbsoluteBrightness(screenBrightness[0]);
if (mScreenBrightnessDarkConfig > bottom) {
Slog.w(TAG, "config_screenBrightnessDark (" + mScreenBrightnessDarkConfig
+ ") should be less than or equal to the first value of "
+ "config_autoBrightnessLcdBacklightValues ("
+ bottom + ").");
}
if (bottom < screenBrightnessRangeMinimum) {
screenBrightnessRangeMinimum = bottom;
}
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp,
ambientLightHorizon, autoBrightnessAdjustmentMaxGamma);
}
}
mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
mColorFadeFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);// false
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (mProximitySensor != null) {
mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
TYPICAL_PROXIMITY_THRESHOLD);
}
}
}
这里用到了clampAbsoluteBrightness()方法,看下是什么意思吧。
private static int clampAbsoluteBrightness(int value) {
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
这里注意下MathUtils.constrain()表示百分比缩放函数,比如MathUtils.constrain(0.5, 0, 255)表示(255-0)*0.5。
我们发现构造方法中并没有特殊的一些功能,简单说下各个参数的大概作用吧。
mBatteryStat:设置屏幕亮度的时候,更新电池电量;
mSensorManager:获取Lsensor来调节背光;
mWindowManagerPolicy:亮屏时调用到window绘制屏幕;
mBlanker:亮屏以及设置背光时调用到DisplayPowerState的中介类对象;
mScreenBrightnessDozeConfig:Doze状态配置亮度;
mScreenBrightnessDimConfig:暗屏状态配置亮度;
mScreenBrightnessDarkConfig:黑屏状态配置亮度;
mScreenBrightnessRangeMaximum:屏幕最大亮度;
screenBrightnessRangMinimum:屏幕最小亮度;
mUseSoftwareAutoBrightnessConfig:是否支持自动亮度;
lightSensorWarmUpTimeConfig:Lsensor启动时间,0;
screenAutoBrightnessSpline:光照/背光mapping对应值;
lightSensorRate:sensor采集数据频率250;
brighteningLightDebounce:变亮防抖时间 2000;
darkeningLightDebounce:变暗防抖时间 4000;
autoBrightnessResetAmbientLuxAfterWarmUp:当sensor启动时重置环境光照值;
ambientLightHorizon:环境光照采集时间阀值,10000;
autoBrightnessAdjustmentMaxGamma:最大gamma值。
在初始化之后要重点说下screenAutoBroghtnessSpline,该参数是通过方法createAutoBrightnessSpline()直接返回一个Spline对象,如下:
private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
if (lux == null || lux.length == 0 || brightness == null || brightness.length == 0) {
Slog.e(TAG, "Could not create auto-brightness spline.");
return null;
}
try {
final int n = brightness.length;
float[] x = new float[n];
float[] y = new float[n];
y[0] = normalizeAbsoluteBrightness(brightness[0]);
for (int i = 1; i < n; i++) {
x[i] = lux[i - 1];
y[i] = normalizeAbsoluteBrightness(brightness[i]);
}
Spline spline = Spline.createSpline(x, y);
if (DEBUG) {
Slog.d(TAG, "Auto-brightness spline: " + spline);
for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
}
}
return spline;
} catch (IllegalArgumentException ex) {
Slog.e(TAG, "Could not create auto-brightness spline.", ex);
return null;
}
}
这里继续看下lux和screenBrightness的配置值:
- 50
- 300
- 400
- 600
- 800
- 1000
- 1300
- 1600
- 2000
- 3000
- 4000
- 20
- 380
- 400
- 475
- 580
- 650
- 750
- 820
- 1100
- 1450
- 1700
- 2047
createAutoBrightnessSpline()方法的效果就是将环境光照lux值1~4000对应到屏幕亮度0~255的值上。由于各个硬件厂商的光感器件配置不同,因此源码上并未提供标准配置,有厂商自行在overlay上配置。
由于亮屏之后屏幕自动亮度才会生效,所以在亮屏的时候,流程会走到DisplayPowerController中的核心函数updatePowerState(),在该函数中会调用AutomaticBrightnessController的configure()方法。
// Configure auto-brightness.
boolean autoBrightnessEnabled = false;
if (mAutomaticBrightnessController != null) {
final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig
&& (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND);
autoBrightnessEnabled = mPowerRequest.useAutoBrightness
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
&& brightness < 0;
final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
&& mPowerRequest.brightnessSetByUser;
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
userInitiatedChange, mPowerRequest.useTwilight);
}
public void configure(boolean enable, float adjustment, boolean dozing,
boolean userInitiatedChange, boolean useTwilight) {
// While dozing, the application processor may be suspended which will prevent us from
// receiving new information from the light sensor. On some devices, we may be able to
// switch to a wake-up light sensor instead but for now we will simply disable the sensor
// and hold onto the last computed screen auto brightness. We save the dozing flag for
// debugging purposes.dozing状态时,应用处理器可能会暂停,以便阻止从Lsensor接收新的数据;
mDozing = dozing;
boolean changed = setLightSensorEnabled(enable && !dozing);//设置Lsensor状态
changed |= setScreenAutoBrightnessAdjustment(adjustment);
changed |= setUseTwilight(useTwilight);
if (changed) {
updateAutoBrightness(false /*sendUpdate*/);
}
if (enable && !dozing && userInitiatedChange) {
prepareBrightnessAdjustmentSample();
}
}
当上面三种情况发生变化时,都会去更新自动亮度,但是这里传入的参数是false,则不会去更新到屏幕上。
当上述条件满足之后,Lsensor采集到光照值,回调到Lsensor监听器mLightSensorListener的onSensorChanged()方法,在该方法中调用handleLightSensorEvent()方法,如下:
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (mLightSensorEnabled) {
final long time = SystemClock.uptimeMillis();//记录当前时间
final float lux = event.values[0];//从sensor中取出光照值
handleLightSensorEvent(time, lux);//处理Lsensor事件
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
private void handleLightSensorEvent(long time, float lux) {
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
applyLightSensorMeasurement(time, lux);
updateAmbientLux(time);
}
private void applyLightSensorMeasurement(long time, float lux) {
mRecentLightSamples++;//Lsensor使能时,光样本采集的次数;
// Store all of the light measurements for the intial horizon period. This is to help
// diagnose dim wake ups and slow responses in b/27951906.//保存初始阶段光测量的所有值
if (time <= mLightSensorEnableTime + mAmbientLightHorizon) {
mInitialHorizonAmbientLightRingBuffer.push(time, lux);//保存Lsensor使能时,前10s的环境光照值
}
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);//将最近11次检测到的环境光值存入数组中,11次之前的去掉。
mAmbientLightRingBuffer.push(time, lux);
// Remember this sample value.
mLastObservedLux = lux;//保存最近的光样本值
mLastObservedLuxTime = time;//保存最近光样本采集的时间
}
可以看到在亮屏后,可是10s采集到的环境光线值复制给mInitialHorizonAmbientLightRingBuffer中,后面超过10s之后的环境光照采集值都会放到mAmbientLightRingBuffer中。prune()方法,保存最近11次的光线变化,每次时间变化都会将11次之前的光线值给剪裁掉。push()操作便是将最新的亮度值不断的送入mAmbientLightRingBuffer数组中。最后将最新的光照值保存到mLastObservedLux变量中,最近光样本采集时间保持到mLastObservedLuxTime变量中。
接着看下updateAmbientLux()方法,如下:
private void updateAmbientLux(long time) {
// If the light sensor was just turned on then immediately update our initial
// estimate of the current ambient light level.Lsensor开启时,亮度需要立即适应当前环境光照来调整屏幕亮度。
if (!mAmbientLuxValid) {
final long timeWhenSensorWarmedUp =
mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;//Lsensor使能时到Lsensor准备好的时间点
if (time < timeWhenSensorWarmedUp) {
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: "
+ "time=" + time
+ ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
}
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
timeWhenSensorWarmedUp);
return;
}
setAmbientLux(calculateAmbientLux(time));
mAmbientLuxValid = true;
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Initializing: "
+ "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
+ ", mAmbientLux=" + mAmbientLux);
}
updateAutoBrightness(true);
}
long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
float ambientLux = calculateAmbientLux(time);
if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
|| ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
setAmbientLux(ambientLux);
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: "
+ ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
+ "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
+ ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
+ ", mAmbientLux=" + mAmbientLux);
}
updateAutoBrightness(true);
nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
}
long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
// If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
// exceed the necessary threshold, then it's possible we'll get a transition time prior to
// now. Rather than continually checking to see whether the weighted lux exceeds the
// threshold, schedule an update for when we'd normally expect another light sample, which
// should be enough time to decide whether we should actually transition to the new
// weighted ambient lux or not.
nextTransitionTime =
nextTransitionTime > time ? nextTransitionTime : time + mLightSensorRate;
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
+ nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
}
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
}
看下nextAmbientLightBrighteningTransition()方法,如下:
private long nextAmbientLightBrighteningTransition(long time) {
final int N = mAmbientLightRingBuffer.size();
long earliestValidTime = time;
for (int i = N - 1; i >= 0; i--) {
if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
break;
}
earliestValidTime = mAmbientLightRingBuffer.getTime(i);
}
return earliestValidTime + mBrighteningLightDebounceConfig;
}
以上函数的作用是从mAmbientLightRingBuffer 循环环境光照lux数组里取出第一个大于变亮阈值的一项,取得其时间,
加上变亮防抖时间mBrighteningLightDebounceConfig(这个在config.xml中可以配置的)。
这里计算的是变亮的环境光照过渡时间。
这里做的意义是,需要变亮的环境光照持续时间大于一个过渡时间nextBrightenTransition,才可以将屏幕亮度变亮。
这样可以避免环境光照只是瞬间升高后马上回复(比如闪光灯),屏幕亮度马上跟着变亮。
这也做算是一种防抖措施了,目的也是尽量在环境光照不发生大的变化时候也维持在同一水平。
这里我们就可以理解这个方法的意义了,当前环境光照ambientLux大于变亮的环境光照阈值mBrighteningLuxThreshold,
并且该环境光照持续的时间已经超过了变亮的过度时间,这时候就可以去调用该函数updateAutoBrightness(true)更新屏幕亮度了,
并且在setAmbientLux中重新计算变亮或者变暗时环境光照的阈值,同时重新计算下一次变亮或者变暗的过渡时间。
在updateAutoBrightness中更新屏幕亮度,这里分析该函数的计算流程。
//当用户没有调整状态栏或者设置里的亮度条,
那么传过来的参数mScreenAutoBrightnessAdjustment便等于0,但是大部用户都是调整过的。
private void updateAutoBrightness(boolean sendUpdate) {
if (!mAmbientLuxValid) {
return;
}
float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);//从mScreenAutoBrightnessSpline中获取到当前环境光照mAmbientLux对应的屏幕亮度值与255的比值value。
float gamma = 1.0f;
if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
&& mScreenAutoBrightnessAdjustment != 0.0f) {
final float adjGamma = MathUtils.pow(mScreenAutoBrightnessAdjustmentMaxGamma,
Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));//pow(x,y)求x的y次方。
gamma *= adjGamma;//计算gamma值,
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
}
}
if (mUseTwilight) {
TwilightState state = mTwilight.getLastTwilightState();
if (state != null && state.isNight()) {
final long duration = state.sunriseTimeMillis() - state.sunsetTimeMillis();
final long progress = System.currentTimeMillis() - state.sunsetTimeMillis();
final float amount = (float) Math.pow(2.0 * progress / duration - 1.0, 2.0);
gamma *= 1 + amount * TWILIGHT_ADJUSTMENT_MAX_GAMMA;
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: twilight amount=" + amount);
}
}
}
if (gamma != 1.0f) {
final float in = value;
value = MathUtils.pow(value, gamma);
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
+ ", in=" + in + ", out=" + value);
}
}
int newScreenAutoBrightness =
clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));//round()四舍五入,计算当前环境光照实际亮度值
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
+ mScreenAutoBrightness + ", newScreenAutoBrightness="
+ newScreenAutoBrightness);
}
mScreenAutoBrightness = newScreenAutoBrightness;
mLastScreenAutoBrightnessGamma = gamma;
if (sendUpdate) {
mCallbacks.updateBrightness();//回调到DisplayPowerController中更新亮度。
}
}
}
mScreenAutoBrightnessAdjustment,当用户没有调整状态栏或设置里的亮度条时,该变量为0,但是大部分用户都调整过。
至此,屏幕亮度自动更新的算法基本已经完成。
下面,列出几点可调节的关键位置:
1、gamma范围调节方法:
device\zeusis\pollux\overlay\packages\apps\Settings\res\values\config.xml
device\zeusis\pollux\overlay\frameworks\base\packages\SystemUI\journeyui_res\values\config.xml
-10%
100%
guamma可以在两个文件中设置,如果修改的话,这两个文件要保持一致。
2、le曲线关闭打开方法
曲线添加的地方 frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java,搜索***-6355即可,
主要关闭updateDisplayPowerStateLocked方法中的修改。
3、step设置方法
step变化的地方 frameworks\base\services\core\java\com\android\server\display\RampAnimator.java中的mAnimationCallback
4、自动环境打开,系统设置中显示里亮度进度条默认位置的设置方法
可以通过overlay的方式修改frameworks\base\packages\SettingsProvider\res\values\defaults.xml中的def_screen_auto_brightness_adj,
该变量对应着Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,表示进度条的默认位置。
0%
5、变量变暗的等待时间设置方法
变亮和变暗有两个值表示防抖时间,位置在frameworks\base\core\res\res\values\config.xml中
2000
4000
6、背光曲线
device/zeusis/pollux/overlay/frameworks/base/core/res/res/values/config.xml:config_autoBrightnessLevels config_autoBrightnessLcdBacklightValues,
根据这两个数组,产生背光曲线。
- 50
- 300
- 400
- 600
- 800
- 1000
- 1300
- 1600
- 2000
- 3000
- 4000
- 20
- 380
- 400
- 475
- 580
- 650
- 750
- 820
- 1100
- 1450
- 1700
- 2047
我们在看下系统设置中开启自动亮度调节时,亮度进度条的逻辑,
处理逻辑在packages/apps/Settings/src/com/android/settings/BrightnessSeekBarPreference.java文件中。
private void updateSeekbar() {
if(mSeekBar == null) return;
if (mAutomatic) {
float value = Settings.System.getFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0,
UserHandle.USER_CURRENT);
mSeekBar.setMax((int) BRIGHTNESS_ADJ_RESOLUTION);
//*/ get auto brightness adj based on config
float fValue = (value - mAutoBrightnessAdjMin)*(BRIGHTNESS_ADJ_RESOLUTION*1f) /(mAutoBrightnessAdjMax - mAutoBrightnessAdjMin);
mSeekBar.setProgress((int) fValue);
/*/
mSeekBar.setProgress((int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f));
//*/
} else {
int value;
value = Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, mMaximumBacklight,
UserHandle.USER_CURRENT);
mSeekBar.setMax(mMaximumBacklight - mMinimumBacklight);
mSeekBar.setProgress(value);
}
}
在updateSeekbar()方法中如果开启了自动亮度调节,if语句成立,
在if语句中获取的value值就是Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ的值,
表示进度条的默认位置,调用SeekBar的setProgress()方法设置进度条的位置。