涉及类:
一.简述
Android屏幕背光属于Android系统中display模块,display是从Power中分出来的,所以和Power有着密不可分的关系。背光调节中,又可以分为手动调节和自动调节两个功能,Android定义背光值0-255。
日常调试过程中,我们可以直接cat/sys/class/leds/lcd-backlight/brightness的值,来获得当前屏幕背光的值。
自动背光手动背光中最核心的当属DisplayPowerControl和AutomaticBrightnessController,两个类。其初始化流程如下:
[->SystemServer.java]
acquireWakeLockInternal(IBinder, int,String, String, WorkSource, String, int, ...)
boostScreenBrightnessInternal(long, int)
goToSleepInternal(long, int, int, int)
handleBatteryStateChangedLocked()
handleSandman()
handleScreenBrightnessBoostTimeout()
handleSettingsChangedLocked()
handleUserActivityTimeout()
napInternal(long, int)
onBootPhase(int)
onReceive(Context, Intent)
removeWakeLockLocked(WakeLock, int)
setDozeOverrideFromDreamManagerInternal(int,int)
setMaximumScreenOffTimeoutFromDeviceAdminInternal(int)
setScreenBrightnessOverrideFromWindowManagerInternal(int)
setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(float)
setTemporaryScreenBrightnessSettingOverrideInternal(int)
setUserActivityTimeoutOverrideFromWindowManagerInternal(long)
setUserInactiveOverrideFromWindowManagerInternal()
systemReady(IAppOpsService)
updatePowerStateLocked()
updateWakeLockDisabledStatesLocked()
userActivityInternal(long, int, int,int)
wakeUpInternal(long, String, int,String, int)
首先DisplayPowerControl的初始化在DisplayManagerService中,
private final class LocalService extends DisplayManagerInternal {
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks,Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
DisplayBlanker blanker = newDisplayBlanker() {
@Override
public voidrequestDisplayState(int state, int brightness) {
// The order ofoperations 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);
}
}
DisplayManagerInternal的本地服务实现,LocalService,当PowerManagerService调用SystemReady的时候,同时也调用了DisplayManagerInternal的initPowerManagement。initPowerManagement该方法比较重要,重点在于提供了一个DisplayBlanker回调,用来与PMS交互设置power相关的状态,还有就是使用LightService设置背光值。
其中还初始化了背光核心类DisplayPowerControl,在DisplayManagerService中,也就requestPowerState方法中使用了DisplayPowerControl,先看看他的构造方法
public DisplayPowerController(Context context,
DisplayPowerCallbacks callbacks,Handler handler,
SensorManager sensorManager,DisplayBlanker blanker) {
DisplayPowerCallbacks在PowerManagerService中实现,Handler是PMS的handler,在DisplayPowerController的构造方法中,初始化了另一个核心类AutomaticBrightnessController。关于Android自动背光的功能所有的控制都在该类中。
2.1中介绍了AutomaticBrightnessController,是自动背光的核心,它是在DisplayPowerController的构造方法中,被初始化的。其构造方法如下:
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
SensorManager sensorManager, SplineautoBrightnessSpline, int lightSensorWarmUpTime,
int brightnessMin, intbrightnessMax, float dozeScaleFactor,
int lightSensorRate, longbrighteningLightDebounceConfig,
long darkeningLightDebounceConfig,boolean resetAmbientLuxAfterWarmUpConfig,
int ambientLightHorizon, floatautoBrightnessAdjustmentMaxGamma )
mSensorManager = sensorManager;//用来获取光感传感器
mScreenAutoBrightnessSpline =autoBrightnessSpline;//光照/背光mapping对应值,主要靠config匹配,系统配置文件中有两个数组:
mAmbientLightHorizon =ambientLightHorizon;
mWeightingIntercept =ambientLightHorizon;
mScreenAutoBrightnessAdjustmentMaxGamma= autoBrightnessAdjustmentMaxGamma;//gamma值,这个默认为300%,他是自动背光调节,计算光值大小的一个系数,该值得大小,体现为,gamma大于1,越来越大时,当环境光照变化时,屏幕背光值反映的很明显。当小于1,越来越小时,环境光变化时,屏幕背光值反映越来越缓慢。一般取值在1的左右。
mScreenAutoBrightnessAdjustment;//当手机设置为自动背光,此时还需要手动调节背光条调节背光,此时该值就是对应着背光条的值大小该值范围大小-1~1。默认为0,代表背光条在最中间位置,最右边代表1,反之则为-1
2.2.1 自动背光流程
下面就是自动背光详细的代码流程:
SensorEventListener mLightSensorListener.onSensorChanged-> handleLightSensorEvent
1.->applyLightSensorMeasurement
2.->updateAmbientLux(time) ->updateAutoBrightness(true) -> Callbacks.updateBrightness()
-> DisplayPowerController.updateBrightness() -> sendUpdatePowerState()->sendUpdatePowerStateLocked()
-> MSG_UPDATE_POWER_STATE -> updatePowerState ->animateScreenBrightness ----调节屏幕亮度
-> DisplayPowerState$PhotonicModulator.run() ->DisplayBlanker.requestDisplayState() -> DisplayManagerService(newDisplayBlanker)
-> DisplayManagerInternal.DisplayPowerCallbacks.onStateChanged
其中animateScreenBrightness这个方法就是设置屏幕背光的入口,配合animateScreenStateChange,改变DisplayPowerState中的state和backlight值,当DisplayPowerState中这两个值都变化时其中的PhotonicModulator线程就会被唤醒,此时便会开始执行设置背光值的操作,标志性log如下:DisplayPowerState: Updatingscreen state: state=ON, backlight=255
这里便会又走进initPowerManagement中初始化的DisplayBlanker,之前我们说该类的作用就是与PMS交互,1.设置power状态(屏幕状态…)2.与Light交互设置背光值。分别对应方法DisplayPowerCallbacks.onDisplayStateChange(state),requestGlobalDisplayStateInternal。
2.2.2 自动背光原理
2.2.1中简述了当手机开启自动背光功能时,代码走的流程,但是实际运行过程中,为了避免频繁的改变手机背光值,必须采取一些操作。使得用户体验更好。
2.2.1代码走到handleLightSensorEvent时,会分成两部分applyLightSensorMeasurement和updateAmbientLux,
private void applyLightSensorMeasurement(long time, float lux) {
mRecentLightSamples++;
// 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);
}
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
// Remember this sample value.
mLastObservedLux = lux;
mLastObservedLuxTime = time;
}
这里需要说明的时,参数time,指的是从开机到现在的毫秒数(手机睡眠的时间不包括在内),所以说这里的一个判断指的是设置完自动背光功能开启之后采集前十秒之内的光线值,但是这个数组在目前代码中只是启到一个参考作用,真正用到的是mAmbientLightRingBuffer,prune就是裁剪,对于为什么裁剪一下,我们这里先暂且放放,push就是讲采集到的光线值放入集合内。
因此这里我们理解为每次当光线传感器接收到光线值时,都会讲之前采集到的值,做一个裁剪操作,然后将本次的光线值存入集合。接着就去执行updateAmbientLux操做,
private void updateAmbientLux(long time) {
// If the light sensor was just turned on then immediately update ourinitial
// estimate of the current ambient light level.
if (!mAmbientLuxValid) {
//这里就是当我们刚设置手机屏幕背光为自动背光时,我们需要手机立即生效的操作
}
long nextBrightenTransition =nextAmbientLightBrighteningTransition(time);
long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
float ambientLux = calculateAmbientLux(time);
if (ambientLux >= mBrighteningLuxThreshold &&nextBrightenTransition <= time
|| ambientLux <=mDarkeningLuxThreshold && nextDarkenTransition <= time) {
setAmbientLux(ambientLux);
updateAutoBrightness(true);
nextBrightenTransition =nextAmbientLightBrighteningTransition(time);
nextDarkenTransition =nextAmbientLightDarkeningTransition(time);
}
long nextTransitionTime = Math.min(nextDarkenTransition,nextBrightenTransition);
nextTransitionTime =
nextTransitionTime > time ?nextTransitionTime : time + mLightSensorRate;
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,nextTransitionTime);
}
nextBrightenTransition下一次变亮的时间nextDarkenTransition下一次变暗的时间,mBrighteningLuxThreshold使屏幕变亮所需要的环境光照阈值,一般为当前光线值的1.1倍,mDarkeningLuxThreshold使屏幕变暗所需要的环境光照阈值,一般为当前光线值的1.2倍,当环境光照小于该数值的时候,屏幕才可能变暗。这里就是之前所说为了避免频繁改变屏幕背光,采取一些操作。使得用户体验更好。
calculateAmbientLux(time)这里就是获取当前时间之前采取的光线值的一个加权平均,权重为采集时间。然后就会设置mAmbientLux为刚刚计算得到的光值。
updateAutoBrightness(true),就是计算出需要设置到屏幕上的光值大小,在前面也介绍过mScreenAutoBrightnessSpline就是用来对应光值和背光值的,其运用的算法就是数学中的样条插值,目的在于使得光线变化时,屏幕光值设置的更加平滑。在updateAutoBrightness操作中,会设置成员mScreenAutoBrightness为当前计算的到的光值,之后的设置过程中会同过getAutomaticScreenBrightness获取其值大小
不管是从SystemUI下拉statubar,从qstile拖动背光条,还是从settings的拖动,他们都会向数据库写入相应的数值。
此时PowerManagerService里的SettingsObserver,一旦检测到数据库有变化,便会直接执行相关更新操作,与自动区别的只是参数是否为auto的不一样。
private void handleSettingsChangedLocked() {
updateSettingsLocked();
updatePowerStateLocked();
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.javab/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 7d986d1..6481cb4 100644
---a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
---a/services/core/java/com/android/server/display/DisplayPowerController.java
+++b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -48,6 +48,13 @@ importandroid.view.WindowManagerPolicy;
import java.io.PrintWriter;
+import android.database.ContentObserver;
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.os.UserHandle;
+
/**
*Controls the power state of the display.
*
@@ -261,6 +268,8 @@ final classDisplayPowerController implements AutomaticBrightnessController.Call
private static final int BRIGHTNESS_RAMP_RATE_FASTER = 800;
+ private BrightnessModeObserver mBrightnessModeObserver;
/**
* Creates the display power controller.
*/
@@ -388,6 +397,35 @@ final classDisplayPowerController implements AutomaticBrightnessController.Call
}
}
+ mBrightnessModeObserver = new BrightnessModeObserver(null);
+ mBrightnessModeObserver.startObserving();
+
+ }
+
+ private class BrightnessModeObserver extends ContentObserver {
+ public BrightnessModeObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ boolean autoBrightness =Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE, 1, UserHandle.USER_CURRENT) ==1;
+ if (!autoBrightness) {
+ int brightness =mPowerState.getScreenBrightness();
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, brightness, UserHandle.USER_CURRENT);
+ }
+ }
+
+ public void startObserving() {
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.unregisterContentObserver(this);
+ cr.registerContentObserver(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
+ false,this);
+ }
}
/**
这里就是在DisplayPowerController增加一个观察者,当是否为自动时,直接获取当前背光值并写入数据库,此时切换时,光值不会改变