Android 亮度自动调节

下拉状态栏有个亮度的进度条,如果开启了亮度自动调节开关,会随着周围光线变化,这个进度条也会随着变化,接下来就是看看这个功能是如何实现的。

源码版本

基于 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:

1
2
3
4
5
6
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//省略部分代码
mBrightnessController = new BrightnessController(this, icon, slider);
}

2、这里进行了 BrightnessController 初始化,来看下:

1
2
3
4
5
public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
//省略部分代码
mBrightnessObserver = new BrightnessObserver(mHandler);
//省略部分代码
}

又进行了 BrightnessObserver 初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/** ContentObserver to watch brightness **/
private class BrightnessObserver extends ContentObserver {
//省略部分代码
private final Uri BRIGHTNESS_FOR_VR_URI =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR);
//Add By WuXiaolong for AutomaticBrightness
private final Uri BRIGHTNESS_ADJ_URI =
Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
public BrightnessObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
onChange(selfChange, null);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (selfChange) return;
if (BRIGHTNESS_MODE_URI.equals(uri)) {
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
}
//省略部分代码
//Add By WuXiaolong for AutomaticBrightness
else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
mBackgroundHandler.post(mUpdateSliderRunnable);
} else {
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
}
for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
cb.onBrightnessLevelChanged();
}
}
public void startObserving() {
final ContentResolver 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);
}
public void stopObserving() {
final ContentResolver cr = mContext.getContentResolver();
cr.unregisterContentObserver(this);
}
}

其实我目前下载的源码,这块功能是不全的,我已经加上了,哪里进行 BrightnessObserver 的 ContentObserver 注册呢?

3、回到 BrightnessDialog#onStart:

1
2
3
4
5
6
@Override
protected void onStart() {
super.onStart();
mBrightnessController.registerCallbacks();
MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
}

4、调用mBrightnessController.registerCallbacks();最终走到 mStartListeningRunnable:

1
2
3
4
5
6
7
8
9
10
11
12
13
private final Runnable mStartListeningRunnable = new Runnable() {
@Override
public void run() {
//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,最终走到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mExternalChange = true;
try {
switch (msg.what) {
//省略部分代码
case MSG_UPDATE_SLIDER:
updateSlider(msg.arg1, msg.arg2 != 0);
break;
//省略部分代码
default:
super.handleMessage(msg);
}
} finally {
mExternalChange = false;
}
}
};

走 updateSlider方法,到 :

1
2
3
4
5
6
7
8
private void animateSliderTo(int target) {
if (!mControlValueInitialized) {
// Don't animate the first value since it's default state isn't mea
mControl.setValue(target);
mControlValueInitialized = true;
}
//省略部分代码
}

5、跳到 ToggleSliderView#setValue:

1
2
3
4
5
6
7
8
@Override
public void setValue(int value) {
//这里正是修改进度条
mSlider.setProgress(value);
if (mMirror != null) {
mMirror.setValue(value);
}
}

接下来就是看看亮度自动调节主要的两个类 DisplayPowerController 和 AutomaticBrightnessController。DisplayPowerController 属于 Display 模块,其控制设备屏幕亮灭、背光、与Power关系密切,这里主要看下屏幕亮度的控制这方面的逻辑。

6、首先,在 DisplayManagerService 中初始化 DisplayPowerController,如下:

1
2
3
4
5
6
7
8
9
10
11
private final class LocalService extends DisplayManagerInternal {
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
//省略部分代码
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
}
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
}

7、接着看下 DisplayPowerController 构造方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public DisplayPowerController(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 = new AutomaticBrightnessController(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():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
private void updatePowerState() {
// Update the power state request.
//省略部分代码
final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
if (autoBrightnessAdjustmentChanged) {
mTemporaryAutoBrightnessAdjustment = Float.NaN;
}
// Use the autobrightness adjustment override if set.
final float autoBrightnessAdjustment;
if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) {
autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment;
mAppliedTemporaryAutoBrightnessAdjustment = true;
} else {
autoBrightnessAdjustment = mAutoBrightnessAdjustment;
mAppliedTemporaryAutoBrightnessAdjustment = false;
}
boolean hadUserBrightnessPoint = 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.
boolean slowChange = false;
if (brightness < 0) {
float newAutoBrightnessAdjustment = 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():

1
2
3
4
5
private float getAutoBrightnessAdjustmentSetting() {
final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT);
return Float.isNaN(adj) ? 0.0f : clampAutoBrightnessAdjustment(adj);
}

继续看下 clampAutoBrightnessAdjustment:

1
2
3
private static float clampAutoBrightnessAdjustment(float value) {
return MathUtils.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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public boolean setAutoBrightnessAdjustment(float adjustment) {
adjustment = MathUtils.constrain(adjustment, -1, 1);
if (adjustment == mAutoBrightnessAdjustment) {
return false;
}
if (DEBUG) {
Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
adjustment);
PLOG.start("auto-brightness adjustment");
}
mAutoBrightnessAdjustment = adjustment;
computeSpline();
return true;
}

9、BrightnessMapper#setAutoBrightnessAdjustment 这个方法调用又回到了 AutomaticBrightnessController#setAutoBrightnessAdjustment:

1
2
3
private boolean setAutoBrightnessAdjustment(float adjustment) {
return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
}

AutomaticBrightnessController#setAutoBrightnessAdjustment调用是来到 AutomaticBrightnessController#configure()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
float brightness, boolean userChangedBrightness, float adjustment,
boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
// 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.
boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
boolean changed = 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);
}
final boolean userInitiatedChange =
userChangedBrightness || userChangedAutoBrightnessAdjustment;
if (userInitiatedChange && enable && !dozing) {
prepareBrightnessAdjustmentSample();
}
changed |= setLightSensorEnabled(enable && !dozing);
if (changed) {
updateAutoBrightness(false /*sendUpdate*/);
}
}

AutomaticBrightnessController#configure()调用来到了 DisplayPowerController #updatePowerState()

这样也知道了 newAutoBrightnessAdjustment,继续 putAutoBrightnessAdjustmentSetting:

1
2
3
4
5
private void putAutoBrightnessAdjustmentSetting(float adjustment) {
mAutoBrightnessAdjustment = adjustment;
Settings.System.putFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, UserHandle.USER_CURRENT);
}

就调到第 4 步 BrightnessObserver#onChange,进度条随之变化,Over!



联系作者

我的微信公众号:吴小龙同学,欢迎关注交流~