背光调节,即亮度调节,根据调节方式可以分为手动调节和自动调节。而手动调节有根据调节UI不同,有式有如下几种:
- 1.在设置->显示中手动调节;
- 2.在SystemUI中手动调节;
- 3.在播放视频时上下滑动界面调节亮度.
本篇文章对手动调节亮度流程做一个总结。
1.设置-显示、SystemUI中调节亮度
Settings和SystemUI中的中亮度调节进度框都是来自于SystemUI中的BrightnessDialog,这里我们主要分析其设置亮度的功能,对于该进度框如何自定义实现不做分析。
当点击或者拖动进度框时,会回调SystemUI.BrightnessController中的onChange()
方法,在这个方法中,会对根据是否自动亮度开启、是否VR模式等分别进行处理,每个分支中,首先会通过Binder调用PMS中的setTemporyScreenBrightnessSettingOverride()
,改变临时亮度值,然后开启一个异步任务,将SettingsProvider中的对应值改变,该方法如下:
@Override
public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
int value, boolean stopTracking) {
updateIcon(mAutomatic);
if (mExternalChange) return;
if (mIsVrModeEnabled) {
//VR模式相关亮度,略去
} else if (!mAutomatic) {//未开启自动调节亮度时
final int val = value + mMinimumBacklight;
//设置背光
setBrightness(val);
if (!tracking ) {
//将亮度值保存在SettingsProvider数据库中
AsyncTask.execute(new Runnable() {
public void run() {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, val,
UserHandle.USER_CURRENT);
}
});
}
} else {//开启自动调节亮度时
//计算得到自动背光亮度调整值,并设置
final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
setBrightnessAdj(adj);
if (!tracking) {
//保存在数据库中
AsyncTask.execute(new Runnable() {
public void run() {
Settings.System.putFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
UserHandle.USER_CURRENT);
}
});
}
}
继续看setBrightness()
:
private void setBrightness(int brightness) {
try {
mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
} catch (RemoteException ex) {
}
}
从以上方法中看出,最终,通过调用PowerManagerService的setTemporaryScreenBrightnessSettingOverride()
方法,将亮度值传给PMS去进行处理。
进入到PMS中,该方法如下:
@Override // Binder call
public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
//权限检查
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long ident = Binder.clearCallingIdentity();
try {
//调用Interal方法
setTemporaryScreenBrightnessSettingOverrideInternal(brightness);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
接着分析:
private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) {
synchronized (mLock) {
//将亮度值设置给了mTemporaryScreenBrightnessSettingOverride变量
if (mTemporaryScreenBrightnessSettingOverride != brightness) {
mTemporaryScreenBrightnessSettingOverride = brightness;
mDirty |= DIRTY_SETTINGS;
updatePowerStateLocked();
}
}
}
经过一系列调用之后,将亮度值设置给了mTemporaryScreenBrightnessSettingOverride变量,然后开始调用updatePowerStateLocked()
。
在下一步分析前,我们先暂停此处,来看看播放视频时如何设置亮度的。
2.播放视频时设置亮度
在播放视频时,可以通过上下滑动界面来设置亮度,当退出播放界面时,又会恢复到原亮度,其调用接口正是PMS中的setScreenBrightnessOverrideFromWindowManager()
方法,在Window模块中的RootWindowContainner.java中:
public void handleMessage(Message msg) {
switch (msg.what) {
case SET_SCREEN_BRIGHTNESS_OVERRIDE:
//调用PMS相关接口
mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
msg.arg1);
break;
......
}
}
}
在PMS中,将上面方法中设置的亮度值作如下设置:
private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
synchronized (mLock) {
//将亮度值设置给了mScreenBrightnessOverrideFromWindowManager变量
if (mScreenBrightnessOverrideFromWindowManager != brightness) {
mScreenBrightnessOverrideFromWindowManager = brightness;
mDirty |= DIRTY_SETTINGS;
updatePowerStateLocked();
}
}
}
可以看到,和Settings或SystemUI中调节亮度不同的时,通过播放视频设置的亮度值,最后是赋值给了mScreenBrightnessOverrideFromWindowManager
,但这两种情况下,最终都调用了updatePowerStateLocked()
方法,所以,此处将这两种情况合二为一进行分析。
共用流程
关于updatePowerStateLocked()
方法,已经在PowerManagerService分析中进行了分析,它是PMS的核心方法,其中调用的updateDisplayPowerStateLocked()
方法用于更新Display,背光调节也和这个方法有关系,这个方法在sdf也已经分析了,这里我们再来分析下此方法中仅和亮度调节相关的逻辑:
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
if (){
// Determine appropriate screen brightness and auto-brightness adjustments.
//是否由用户设置标记值,用来决定使用自动亮度还是手动设置亮度
boolean brightnessSetByUser = true;
//需要设置的亮度值,默认为config.xml中config_screenBrightnessSettingDefault的值
int screenBrightness = mScreenBrightnessSettingDefault;
//自动背光调节比例值
float screenAutoBrightnessAdjustment = 0.0f;
//根据Settings Provider中的值Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC判断是否开启了自动亮度调节
//Settings中如果开启该开关,则将会设置如下值
boolean autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
if (!mBootCompleted) {
// Keep the brightness steady during boot. This requires the
// bootloader brightness and the default brightness to be identical.
autoBrightness = false;
brightnessSetByUser = false;
} else if (mIsVrModeEnabled) {//VR模式下
screenBrightness = mScreenBrightnessForVrSetting;
autoBrightness = false;
//由setScreenBrightnessOverrideFromWindowManager()方法设置的亮度值
} else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
screenBrightness = mScreenBrightnessOverrideFromWindowManager;
autoBrightness = false;
brightnessSetByUser = false;
//由setTemporaryScreenBrightnessSettingOverride()方法设置的亮度值
} else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
screenBrightness = mTemporaryScreenBrightnessSettingOverride;
//Settings.System.SCREEN_BRIGHTNESS的值,即保存在数据库中的亮度值,亮度值设置完成后,都会进行保存
} else if (isValidBrightness(mScreenBrightnessSetting)) {
screenBrightness = mScreenBrightnessSetting;
}
//如果自动调节亮度开启,则只需要获得自动调节亮度比例值即可
if (autoBrightness) {
//将亮度值设置为默认亮度,即亮度的调节和手动设置的无关(开启自动调节亮度,手动调节时打印screenBrightness log可验证)
screenBrightness = mScreenBrightnessSettingDefault;
if (isValidAutoBrightnessAdjustment(
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
screenAutoBrightnessAdjustment =
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
} else if (isValidAutoBrightnessAdjustment(
mScreenAutoBrightnessAdjustmentSetting)) {
screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
}
}
// Update display power request.
//封装到mDisplayPowerRequest中,去请求Display
mDisplayPowerRequest.screenBrightness = screenBrightness;
mDisplayPowerRequest.screenAutoBrightnessAdjustment =
screenAutoBrightnessAdjustment;
mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
mDisplayPowerRequest.useAutoBrightness = autoBrightness;
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
}
return mDisplayReady && !oldDisplayReady;
}
结合以上的分析,我们可以得出以下4个结论:
- 1.通过Settings/SystemUI设置亮度值时,亮度值设置给了
mTemporaryScreenBrightnessSettingOverride
变量; - 2.播放视频界面设置亮度值时,设置给了
mScreenBrightnessOverrideFromWindowManager
变量; - 3.如果开启了自动调节亮度开关,虽然拖动亮度调节进度条可以活动,但是实际上跟手动设置的这两个变量值无关,而只和亮度调节比例值相关(至于其中的细节,在下面分析)。
- 4.以上亮度设置值,优先级为:自动调节亮度 > 视频播放时设置亮度 > Settings、SystemUI中设置亮度(因为autoBrightness时将screenBrightness重置了)。
接下来的流程,在DisplayPowerController分析中分析过了,请求Display时,最终会到DisplayPowerController的updatePowerState()
方法中,这里再看看此方法中亮度值相关的流程(有删减):
private void updatePowerState() {
synchronized (mLock) {
//表示要设置的亮度值,并初始化为默认值-1
int brightness = PowerManager.BRIGHTNESS_DEFAULT;
switch (mPowerRequest.policy) {
case DisplayPowerRequest.POLICY_DOZE:
if (!mAllowAutoBrightnessWhileDozingConfig) {
//亮度值设置为mPowerRequest.dozeScreenBrightness
brightness = mPowerRequest.dozeScreenBrightness;
}
}
// 如果灭屏,设置为0
if (state == Display.STATE_OFF) {
brightness = PowerManager.BRIGHTNESS_OFF;
}
//如果开启了亮度增强,将亮度值设置为255
if (mPowerRequest.boostScreenBrightness
&& brightness != PowerManager.BRIGHTNESS_OFF) {
brightness = PowerManager.BRIGHTNESS_ON;
}
// Apply auto-brightness.
//如果不满足以上条件,说明此时亮度值还未设置
if (brightness < 0) {
//自动调节亮度值是否可用
if (autoBrightnessEnabled) {
//如果可用,则从负责自动调节亮度的mAutomaticBrightnessController中获取亮度值
brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
}
if (brightness >= 0) {
// 说明此时使用了自动亮度调节中的亮度值,对该值再次进行筛选
brightness = clampScreenBrightness(brightness);
//如果AUTOBrightness可用,且自动亮度调节比例值未发生变化,则说明是由LightSensor自动调节亮度,缓慢变化
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
mAppliedAutoBrightness = true;
} else {
mAppliedAutoBrightness = false;
}
} else {
mAppliedAutoBrightness = false;
}
// 如果当前亮度值还未设置且当前为Doze状态,则将亮度值设置为配置文件中配置的config_screenBrightnessDoze值
if (brightness < 0 && (state == Display.STATE_DOZE
|| state == Display.STATE_DOZE_SUSPEND)) {
brightness = mScreenBrightnessDozeConfig;
}
//如果到这里还未设置亮度值,则直接使用从PowerMangerService中传过来的、手动设置的值
if (brightness < 0) {
brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
}
//如果进入DIM状态,则亮度值为当前获取的亮度值和其他配置值限制
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightness > mScreenBrightnessRangeMinimum) {
brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
}
if (!mAppliedDimming) {
slowChange = false;
}
mAppliedDimming = true;
} else if (mAppliedDimming) {
slowChange = false;//如果是Dim状态而调整亮度,就不需要缓慢变化
mAppliedDimming = false;
}
//如果当前处于低电量模式,需要亮度进行减半
if (mPowerRequest.lowPowerMode) {
if (brightness > mScreenBrightnessRangeMinimum) {
final float brightnessFactor =
Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
final int lowPowerBrightness = (int) (brightness * brightnessFactor);
brightness = Math.max(lowPowerBrightness, mScreenBrightnessRangeMinimum);
}
}
boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
if ((state == Display.STATE_ON //亮屏
&& mSkipRampState == RAMP_STATE_SKIP_NONE
|| state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig)
&& !wasOrWillBeInVr) {
//设置亮度值,根据slowChange设置快速或慢速动画
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
} else {
//直接设置亮度值,不需要亮度动画
animateScreenBrightness(brightness, 0);
}
}
}
在以上方法中,我们可以看到,PowerManagerService中仅仅将手动调节亮度值进行了赋值,在DisplayPowerController中还需要进行多种决策,以确定最终的亮度值。这里我先用图的形式对以上方法中的决策亮度流程进行描述:
结合图和代码,对最终亮度的决策如下:
- 第1步.当要请求进入Doze状态时,如果配置了Doze下LightSensor不可用,则将亮度设置为
dozeScreenBrightness
,这个值从PMS中而来; - 第2步.当要灭屏时,直接将亮度设置为0;
- 第3步.当设置了亮度增强时,直接将亮度值设置为255(最大值);
- 第4步.如果不满足以上三步,且自动调节亮度开启,则获取自动调节的亮度;
- 第5步.如果不满足以上四步,且当前为DOZE状态,则将亮度设置为
mScreenBrightnessDozeConfig
; - 第6步.如果不满足以上五步,则使用手动设置的亮度值,即从PMS中得到的亮度值;
- 第7步.如果要请求进入DIM状态时,则需要将当前得到的亮度值-10,并和
mScreenBrightnessDimConfig
比较取最小,和mScreenBrightnessRangeMinimum
比较取最大。 - 第8步.如果当前处于低电量模式,则需要将当前得到的亮度值* 低电量模式下亮度缩放比例,然后和
mScreenBrightnessRangeMinimum
取最大(一般缩放值为0.5,即减半);
经过以上8步后,才会得到最终的亮度值。
当亮度值确定了以后,接下来调用animateScreenBrightness()
开始设置背光的亮度了,关于该方法在DisplayPOwerController分析中也已经分析过了,因此接下来的流程,就不再进行了。
结合整个亮度设置过程来看,手动调节亮度并不复杂。下一篇文章中,将会对自动调节亮度进行分析。