下拉状态栏有个亮度的进度条,如果开启了亮度自动调节开关,会随着周围光线变化,这个进度条也会随着变化,接下来就是看看这个功能是如何实现的。
源码版本
基于 Android 9.0 分析。
BrightnessDialog,位于:frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
ToggleSliderView,位于:frameworks/base/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java
DisplayPowerController,位于:frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
AutomaticBrightnessController,位于:frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java
BrightnessMappingStrategy,
概述
状态栏里亮度页面是 BrightnessDialog,其中进度条设置是 ToggleSliderView,亮度自动调节主要是 DisplayPowerController 和 AutomaticBrightnessController 两个类,当亮度发生变化时,如果关联到 ToggleSliderView,用的是 ContentObserver,Uri 为 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ。
源码梳理
1、BrightnessDialog#onCreate:
@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//省略部分代码
mBrightnessController = newBrightnessController( this, icon, slider);
}
2、这里进行了 BrightnessController 初始化,来看下:
publicBrightnessController(Context context, ImageView icon, ToggleSlider control){
//省略部分代码
mBrightnessObserver = newBrightnessObserver(mHandler);
//省略部分代码
}
又进行了 BrightnessObserver 初始化:
/** ContentObserver to watch brightness **/
privateclassBrightnessObserverextendsContentObserver{
//省略部分代码
privatefinalUri BRIGHTNESS_FOR_VR_URI =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR);
//Add By WuXiaolong for AutomaticBrightness
privatefinalUri BRIGHTNESS_ADJ_URI =
Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
publicBrightnessObserver(Handler handler){
super(handler);
}
@Override
publicvoidonChange(booleanselfChange){
onChange(selfChange, null);
}
@Override
publicvoidonChange(booleanselfChange, Uri uri){
if(selfChange) return;
if(BRIGHTNESS_MODE_URI.equals(uri)) {
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
}
//省略部分代码
//Add By WuXiaolong for AutomaticBrightness
elseif(BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
mBackgroundHandler.post(mUpdateSliderRunnable);
} else{
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
}
for(BrightnessStateChangeCallback cb : mChangeCallbacks) {
cb.onBrightnessLevelChanged();
}
}
publicvoidstartObserving(){
finalContentResolver cr = mContext.getContentResolver();
cr.unregisterContentObserver( this);
//省略部分代码
cr.registerContentObserver(
BRIGHTNESS_FOR_VR_URI,
false, this, UserHandle.USER_ALL);
//Add By WuXiaolong for AutomaticBrightness
cr.registerContentObserver(
BRIGHTNESS_ADJ_URI,
false, this, UserHandle.USER_ALL);
}
publicvoidstopObserving(){
finalContentResolver cr = mContext.getContentResolver();
cr.unregisterContentObserver( this);
}
}
其实我目前下载的源码,这块功能是不全的,我已经加上了,哪里进行 BrightnessObserver 的 ContentObserver 注册呢?
3、回到 BrightnessDialog#onStart:
@Override
protectedvoidonStart(){
super.onStart();
mBrightnessController.registerCallbacks();
MetricsLogger.visible( this, MetricsEvent.BRIGHTNESS_DIALOG);
}
4、调用mBrightnessController.registerCallbacks();最终走到 mStartListeningRunnable:
privatefinalRunnable mStartListeningRunnable = newRunnable() {
@Override
publicvoidrun(){
//BrightnessObserver 注册
mBrightnessObserver.startObserving();
mUserTracker.startTracking();
// Update the slider and mode before attaching the listener so we don't
// receive the onChanged notifications for the initial values.
mUpdateModeRunnable.run();
mUpdateSliderRunnable.run();
mHandler.sendEmptyMessage(MSG_ATTACH_LISTENER);
}
};
当亮度有变化时,会走 BrightnessObserver#onChange,最终走到:
privatefinalHandler mHandler = newHandler() {
@Override
publicvoidhandleMessage(Message msg){
mExternalChange = true;
try{
switch(msg.what) {
//省略部分代码
caseMSG_UPDATE_SLIDER:
updateSlider(msg.arg1, msg.arg2 != 0);
break;
//省略部分代码
default:
super.handleMessage(msg);
}
} finally{
mExternalChange = false;
}
}
};
走 updateSlider方法,到 :
privatevoidanimateSliderTo(inttarget){
if(!mControlValueInitialized) {
// Don't animate the first value since it's default state isn't mea
mControl.setValue(target);
mControlValueInitialized = true;
}
//省略部分代码
}
5、跳到 ToggleSliderView#setValue:
@Override
publicvoidsetValue(intvalue){
//这里正是修改进度条
mSlider.setProgress(value);
if(mMirror != null) {
mMirror.setValue(value);
}
}
接下来就是看看亮度自动调节主要的两个类 DisplayPowerController 和 AutomaticBrightnessController。DisplayPowerController 属于 Display 模块,其控制设备屏幕亮灭、背光、与Power关系密切,这里主要看下屏幕亮度的控制这方面的逻辑。
6、首先,在 DisplayManagerService 中初始化 DisplayPowerController,如下:
privatefinalclassLocalServiceextendsDisplayManagerInternal{
@Override
publicvoidinitPowerManagement(finalDisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager){
synchronized(mSyncRoot) {
//省略部分代码
mDisplayPowerController = newDisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
}
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
}
7、接着看下 DisplayPowerController 构造方法,如下:
publicDisplayPowerController(Context context,
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker){
//省略部分代码
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
//省略部分代码
if(mUseSoftwareAutoBrightnessConfig) {
//省略部分代码
mBrightnessMapper = BrightnessMappingStrategy.create(resources);
if(mBrightnessMapper != null) {
mAutomaticBrightnessController = newAutomaticBrightnessController( this,
handler.getLooper(), sensorManager, mBrightnessMapper,
lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, hysteresisLevels);
} else{
mUseSoftwareAutoBrightnessConfig = false;
}
}
//省略部分代码
mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
mTemporaryAutoBrightnessAdjustment = Float.NaN;
//省略部分代码
}
由于亮屏之后屏幕自动亮度才会生效,所以在亮屏的时候,流程会走到 DisplayPowerController 中的核心函数 updatePowerState():
privatevoidupdatePowerState(){
// Update the power state request.
//省略部分代码
finalbooleanautoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
if(autoBrightnessAdjustmentChanged) {
mTemporaryAutoBrightnessAdjustment = Float.NaN;
}
// Use the autobrightness adjustment override if set.
finalfloatautoBrightnessAdjustment;
if(!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) {
autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment;
mAppliedTemporaryAutoBrightnessAdjustment = true;
} else{
autoBrightnessAdjustment = mAutoBrightnessAdjustment;
mAppliedTemporaryAutoBrightnessAdjustment = false;
}
booleanhadUserBrightnessPoint = false;
// Configure auto-brightness.
if(mAutomaticBrightnessController != null) {
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mBrightnessConfiguration,
mLastUserSetScreenBrightness / ( float) PowerManager.BRIGHTNESS_ON,
userSetBrightnessChanged, autoBrightnessAdjustment,
autoBrightnessAdjustmentChanged, mPowerRequest.policy);
}
// Apply auto-brightness.
booleanslowChange = false;
if(brightness < 0) {
floatnewAutoBrightnessAdjustment = autoBrightnessAdjustment;
if(autoBrightnessEnabled) {
brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
newAutoBrightnessAdjustment =
mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
}
if(brightness >= 0) {
// Use current auto-brightness value and slowly adjust to changes.
brightness = clampScreenBrightness(brightness);
if(mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
// Tell the rest of the system about the new brightness. Note that we do this
// before applying the low power or dim transformations so that the slider
// accurately represents the full possible range, even if they range changes what
// it means in absolute terms.
putScreenBrightnessSetting(brightness);
mAppliedAutoBrightness = true;
} else{
mAppliedAutoBrightness = false;
}
if(autoBrightnessAdjustment != newAutoBrightnessAdjustment) {
// If the autobrightness controller has decided to change the adjustment value
// used, make sure that's reflected in settings.
putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment);
}
} else{
mAppliedAutoBrightness = false;
}
//省略部分代码
}
接下来分别看看 autoBrightnessAdjustment 和 newAutoBrightnessAdjustment 怎么来的?
autoBrightnessAdjustment 是来自 mTemporaryAutoBrightnessAdjustment 或 mAutoBrightnessAdjustment 赋值,mAutoBrightnessAdjustment 在第 7 步mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();有初始化,看下 getAutoBrightnessAdjustmentSetting():
privatefloatgetAutoBrightnessAdjustmentSetting(){
finalfloatadj = Settings.System.getFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT);
returnFloat.isNaN(adj) ? 0.0f: clampAutoBrightnessAdjustment(adj);
}
继续看下 clampAutoBrightnessAdjustment:
privatestaticfloatclampAutoBrightnessAdjustment(floatvalue){
returnMathUtils.constrain( value, -1.0f, 1.0f);
}
这里注意下 MathUtils.constrain() 表示百分比缩放函数,比如 MathUtils.constrain(0.5, 0, 255) 表示 (255-0)*0.5。
这样了解了 autoBrightnessAdjustment,接下来看 newAutoBrightnessAdjustment。
8、回到 DisplayPowerController#updatePowerState(),看到 newAutoBrightnessAdjustment 调用了 AutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment(),最终是到了 BrightnessMapper#getAutoBrightnessAdjustment() 其中 mAutoBrightnessAdjustment 变量,赋值是在 BrightnessMapper#setAutoBrightnessAdjustment:
@Override
publicbooleansetAutoBrightnessAdjustment(floatadjustment){
adjustment = MathUtils.constrain(adjustment, - 1, 1);
if(adjustment == mAutoBrightnessAdjustment) {
returnfalse;
}
if(DEBUG) {
Slog.d(TAG, "setAutoBrightnessAdjustment: "+ mAutoBrightnessAdjustment + " => "+
adjustment);
PLOG.start( "auto-brightness adjustment");
}
mAutoBrightnessAdjustment = adjustment;
computeSpline();
returntrue;
}
9、BrightnessMapper#setAutoBrightnessAdjustment 这个方法调用又回到了 AutomaticBrightnessController#setAutoBrightnessAdjustment:
privatebooleansetAutoBrightnessAdjustment(floatadjustment){
returnmBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
}
AutomaticBrightnessController#setAutoBrightnessAdjustment调用是来到 AutomaticBrightnessController#configure()方法:
publicvoidconfigure(booleanenable, @Nullable BrightnessConfiguration configuration,
floatbrightness, booleanuserChangedBrightness, floatadjustment,
booleanuserChangedAutoBrightnessAdjustment, intdisplayPolicy){
// 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.
booleandozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
booleanchanged = setBrightnessConfiguration(configuration);
changed |= setDisplayPolicy(displayPolicy);
if(userChangedAutoBrightnessAdjustment) {
changed |= setAutoBrightnessAdjustment(adjustment);
}
if(userChangedBrightness && enable) {
// Update the brightness curve with the new user control point. It's critical this
// happens after we update the autobrightness adjustment since it may reset it.
changed |= setScreenBrightnessByUser(brightness);
}
finalbooleanuserInitiatedChange =
userChangedBrightness || userChangedAutoBrightnessAdjustment;
if(userInitiatedChange && enable && !dozing) {
prepareBrightnessAdjustmentSample();
}
changed |= setLightSensorEnabled(enable && !dozing);
if(changed) {
updateAutoBrightness( false/*sendUpdate*/);
}
}
AutomaticBrightnessController#configure()调用来到了 DisplayPowerController #updatePowerState()。
这样也知道了 newAutoBrightnessAdjustment,继续 putAutoBrightnessAdjustmentSetting:
privatevoidputAutoBrightnessAdjustmentSetting(floatadjustment){
mAutoBrightnessAdjustment = adjustment;
Settings.System.putFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, UserHandle.USER_CURRENT);
}
就调到第 4 步 BrightnessObserver#onChange,进度条随之变化,Over!