sunwengang blog

developer | android display/graphics

  1. 1. SystemUI-settings手动背光调节
    1. 1.1. 函数调用流程
    2. 1.2. 部分代码梳理
    3. 1.3. 异步任务机制AsyncTask
      1. 1.3.1. 异步任务主要方法
  2. 2. 自动背光调节
    1. 2.1. 主要变量
    2. 2.2. DisplayPowerController初始化背光属性变量
    3. 2.3. 创建背光曲线(映射)
      1. 2.3.1. 创建曲线示意图
    4. 2.4. 构造函数开始创建
    5. 2.5. (1) PhysicalMappingStrategy构造函数
    6. 2.6. (1.1) PhysicalMappingStrategy中的computeSpline
      1. 2.6.1. Pair容器类
    7. 2.7. (2) SimpleMappingStrategy构造函数
    8. 2.8. (2.1) SimpleMappingStrategy中的computeSpline
  3. 3. AutomaticBrightnessController初始化
    1. 3.1. *configure方法配置AutomaticBrightnessController
      1. 3.1.1. 1. setBrightnessConfiguration
      2. 3.1.2. 2. setDisplayPolicy
      3. 3.1.3. 3. setAutoBrightnessAdjustment
      4. 3.1.4. 4. setScreenBrightnessByUser
      5. 3.1.5. 5. prepareBrightnessAdjustmentSample
      6. 3.1.6. 6. setLightSensorEnabled
      7. 3.1.7. 7. *updateAutoBrightness自动背光获取
    2. 3.2. adjustment变量计算
      1. 3.2.1. 用户手动调节亮度条
  4. 4. debug调试
  5. 5. 参考

参考Android R源码,对背光手动调节、自动调节的流程作简单梳理。

SystemUI-settings手动背光调节

函数调用流程

1
2
3
4
5
6
7
frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java - onChanged  ---->
setBrightness ---->
frameworks/base/core/java/android/hardware/display/DisplayManager.java - setTemporaryBrightness ---->
frameworks/base/core/java/android/hardware/display/DisplayManagerGlobal.java - setTemporaryBrightness [调用IDisplayManager.aidl的setTemporaryBrightness]--->
frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java - setTemporaryBrightness [binder call跨进程 APP进程到DMS进程]
frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java - setTemporaryBrightness [消息处理] ---->
updatePowerState* [主要设置、实现背光函数]

调用流程图

部分代码梳理

  1. BrightnessController.java设置背光:
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
64
65
66
//frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@Override
public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
int value, boolean stopTracking) {
....
final float minBacklight;
final float maxBacklight;
final int metric;
final String settingToChange;

//获取背光值
//value入参,Gamma转换成线性
//valFloat:根据亮度条的拖动,计算出新的亮度值
final float valFloat = MathUtils.min(convertGammaToLinearFloat(value,
minBacklight, maxBacklight),
1.0f);
....
//设置背光值
setBrightness(valFloat);
if (!tracking) {
//在异步任务中将新的亮度值保存在SettingsProvider中
AsyncTask.execute(new Runnable() {
public void run() {
Settings.System.putFloatForUser(mContext.getContentResolver(),
settingToChange, valFloat, UserHandle.USER_CURRENT);
}
});
}
for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
cb.onBrightnessLevelChanged();
}
}

//设置背光值
private void setBrightness(float brightness) {
//DisplayManagerService对象
mDisplayManager.setTemporaryBrightness(brightness);
}

//frameworks/base/packages/SettingsLib/src/com/android/settingslib/display/BrightnessUtils.java
// Hybrid Log Gamma constant values
private static final float R = 0.5f;
private static final float A = 0.17883277f;
private static final float B = 0.28466892f;
private static final float C = 0.55991073f;

public static final float convertGammaToLinearFloat(int val, float min, float max) {
// 计算 (val-GAMMA_SPACE_MIN) / (GAMMA_SPACE_MAX-GAMMA_SPACE_MAX)
//最大值减去最小值评价一组数据的离散度,即极差
final float normalizedVal = MathUtils.norm(GAMMA_SPACE_MIN, GAMMA_SPACE_MAX, val); //min 0, max 65535
final float ret;
//对调用者自身的rgb值平方或开放
if (normalizedVal <= R) {
ret = MathUtils.sq(normalizedVal / R); //开方根
} else {
ret = MathUtils.exp((normalizedVal - C) / A) + B; //以自然常数e为底的指数函数
}

// HLG is normalized to the range [0, 12], ensure that value is within that range,
// it shouldn't be out of bounds.
final float normalizedRet = MathUtils.constrain(ret, 0, 12);

// Re-normalize to the range [0, 1]
// in order to derive the correct setting value.
return MathUtils.lerp(min, max, normalizedRet / 12);
}
  1. AIDL跨进程(bind call)到DMS.java
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
@VisibleForTesting
final class BinderService extends IDisplayManager.Stub {
.....
@Override // Binder call
public void setTemporaryBrightness(float brightness) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
"Permission required to set the display's brightness");
final long token = Binder.clearCallingIdentity();
try {
//同步执行代码块
//保证在同一时刻最多只有一个线程执行该段代码
synchronized (mSyncRoot) {
mDisplayPowerController.setTemporaryBrightness(brightness);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}

//frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
public void setTemporaryBrightness(float brightness) {
//mHandler是DisplayControllerHandler类型
//创建message(省去了创建对象申请内存的开销,相比new message)
Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS,
Float.floatToIntBits(brightness), 0 /*unused*/);
//内部调用sendMessage,即发送消息
msg.sendToTarget();
}

private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
//消息处理
case MSG_SET_TEMPORARY_BRIGHTNESS:
//入参int,返回float类型,赋值给mTemporaryScreenBrightness
mTemporaryScreenBrightness = Float.intBitsToFloat(msg.arg1);
updatePowerState();
break;
...
}
}

//主要实现函数
private void updatePowerState() {
// Update the power state request.
final boolean mustNotify;
final int previousPolicy;
boolean mustInitialize = false;
int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
...
// 如果power状态变化,则第一时间初始化更新
if (mustInitialize) {
initialize();
}
...
//获取p-sensor距离感应器(Apply the proximity sensor)
if (mProximitySensor != null) {
...
}
//1. 手动设置亮度是否改变
final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();

//如果没有覆盖,则使用手动设置的临时背光
if (isValidBrightnessValue(mTemporaryScreenBrightness)) {
//2. 将手动设置的背光值 赋值给 brightnessState
brightnessState = mTemporaryScreenBrightness;
mAppliedTemporaryBrightness = true;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_TEMPORARY);
} else {
mAppliedTemporaryBrightness = false;
}

final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
if (autoBrightnessAdjustmentChanged) {
mTemporaryAutoBrightnessAdjustment = Float.NaN;
}
//如果设置了,则使用自动背光覆盖
final float autoBrightnessAdjustment;
if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) {
autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment;
brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO_TEMP;
mAppliedTemporaryAutoBrightnessAdjustment = true;
} else {
autoBrightnessAdjustment = mAutoBrightnessAdjustment;
brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO;
mAppliedTemporaryAutoBrightnessAdjustment = false;
}
....
// Apply auto-brightness.
boolean slowChange = false;
if (Float.isNaN(brightnessState)) {
float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
if (autoBrightnessEnabled) {
//获取自动背光值
brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness();
//获取新的adjustment值
newAutoBrightnessAdjustment =
mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
}
if (isValidBrightnessValue(brightnessState)
|| brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) {
// Use current auto-brightness value and slowly adjust to changes.
//3. 使用当前的自动背光值,缓慢的变化
brightnessState = clampScreenBrightness(brightnessState);
.....
}
if (autoBrightnessAdjustment != newAutoBrightnessAdjustment) {
//将adjustment值保存到SettingsProvider中
//以确保Settings等其他进程对它的使用
putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment);
} else {
// Adjustment values resulted in no change
brightnessAdjustmentFlags = 0;
}
}
.....
float animateValue = brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT
? PowerManager.BRIGHTNESS_MIN : brightnessState;
if (isValidBrightnessValue(animateValue)) {
if (initialRampSkip || hasBrightnessBuckets
|| wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
//4. 设置背光到底层LED驱动,调节背光值,不设置背光动画(并且防止非法值时,保证不黑屏,设置最小背光)
animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM);
} else {
//设置亮度值到底层驱动,调节背光值,根据slowChange设置快动画还是慢动画
animateScreenBrightness(animateValue,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
}
}
}

//--------------------------------

//1.手动设置的亮度
private boolean updateUserSetScreenBrightness() {
//mPendingScreenBrightnessSetting是通过SettingsObserver监测Settings数据库中的值
//在handleSettingsChange方法中通过getScreenBrightnessSetting()获取
if ((Float.isNaN(mPendingScreenBrightnessSetting)
|| mPendingScreenBrightnessSetting < 0.0f)) {
return false;
}
if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) {
mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
//手动设置的背光
mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
return false;
}
mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting;
mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting;
mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; //not a number, 0.0f / 0.0f
return true;
}

private float clampScreenBrightness(float value) {
//非法值则返回最小背光值
if (Float.isNaN(value)) {
return mScreenBrightnessRangeMinimum;
}
//当前背光值在最小背光和最大背光之间进行百分比缩放
return MathUtils.constrain(
value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
}

private void animateScreenBrightness(float target, float rate) {
if (DEBUG) {
Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
}
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target);
// TODO(b/153319140) remove when we can get this from the above trace invocation
SystemProperties.set("debug.tracing.screen_brightness", String.valueOf(target));
try {
// TODO(brightnessfloat): change BatteryStats to use float
mBatteryStats.noteScreenBrightness(
BrightnessSynchronizer.brightnessFloatToInt(
mContext, target));
} catch (RemoteException ex) {
// same process
}
}
}

异步任务机制AsyncTask

在Android中实现异步任务机制有两种方式:Handler和AsyncTask

相比于Handle模式需为每个文物创建新县城,发送消息接受消息过程精细,工具类android.os.AsyncTask使创建异步任务变得更加简单

注意点:

  1. 实例必须在UI线程中创建
  2. execute必须在UI线程中调用
  3. 不要手动调用onPreExecute,doInBackground,onProgressUpdate,onPostExecute方法
  4. 不能在doInBackground(Params… params)中更改UI组件的信
  5. 一个任务实例只能执行一次,如果执行第二次将会抛出异常

异步任务主要方法

AsyncTask是一个泛型类,它的三个类型参数的含义如下:

  1. Params:doInBackground方法的参数类型;
  2. Progress:AsyncTask所执行的后台任务的进度类型;
  3. Result:后台任务的返回结果类型。

方法:

  1. execute(Params… params),执行一个异步任务,需要在代码中调用此方法,触发异步任务的执行
  2. onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记
  3. doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息
  4. onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上
  5. onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件

自动背光调节

主要变量

代码主要在frameworks/base/services/core/java/com/android/server/display目录下的DisplayPowerController.javaAutomaticBrightnessController.java

  1. AutomaticBrightnessController.java中定义了一些自动背光的变量:
  • mScreenAutoBrightness:屏幕亮度级别是由自动亮度算法决定的,实际的亮度应向这个值靠拢。我们保留这个值,即使我们停止使用光传感器,以便我们可以快速恢复到之前的自动亮度级别
  • mResetAmbientLuxAfterWarmUpConfig:如果设置为true,屏幕点亮后,控制器根据当前传感器读到的值调整亮度;如果是false,控制器将收集更多的数据,然后决定是否改变亮度
  • mAmbientLux:当前接收的环境光级别
  • mAmbientLightRingBuffer:用来保存最近环境光传感器读值的环形传感器
  • AMBIENT_LIGHT_PREDICTION_TIME_MILLIS=100:假定当前传感器读数超出当前时间的有效期,并且确保最后样本的权重非0,这反过来确保了总权重非0
  • mLightSensorWarmUpTimeConfig:亮屏后在等待光传感器准备时自动亮度调整时间,以毫秒为单位。该值在创建AutomaticBrightnessController对象时被入参赋值
  1. BrightnessMappingStrategy类负责创建背光曲线(从BrightnessConfigure类中读取两个数组源:config_autoBrightnessLevels和config_autoBrightnessDisplayValuesNits),计算自动背光值

  2. 背光相关名词

  • 光照度(照度):从光源照射到单位面积上的光通量,以E表示,照度的单位为勒克斯(Lux)

DisplayPowerController初始化背光属性变量

  1. 首先通过initPowerManagement方法new一个DisplayPowerController对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    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, float brightness) {
.......
};
//创建DisplayPowerController对象
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker,
mDisplayDevices.get(Display.DEFAULT_DISPLAY));
mSensorManager = sensorManager;
}

mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
}
  1. DisplayPowerController构造函数中初始化了很多和亮度相关的属性变量。
  • mBatteryStats:获取电池信息service状态用于更新电池电量
  • mSensorManager:获取SensorManager用于调节吧诶广
  • mWindowManagerPolicy: 亮屏时调用到window绘制屏幕
  • mBlanker:亮屏以及设置背光时调用到DisplayPowerState的中介类对象
  • mScreenBrightnessDozeConfig:Doze状态配置亮度
  • mScreenBrightnessDimConfig:暗屏状态配置亮度
  • mScreenBrightnessRangeMaximum:屏幕最大亮度
  • mScreenBrightnessRangeMinimum:屏幕最小亮度
  • mUseSoftwareAutoBrightnessConfig:是否支持自动亮度
  • lightSensorWarmUpTimeConfig:Light sensor启动时间
  • lightSensorRate:sensor采集数据频率,配置在frameworks/base/core/res/res/values/config.xml,默认250
  • brighteningLightDebounce:变亮防抖时间,同上,默认4000
  • darkeningLightDebounce:变暗防抖时间,同上,默认8000
  • autoBrightnessResetAmbientLuxAfterWarmUp:当sensor启动时重置环境光照值,同上,默认true

创建背光曲线(映射)

创建曲线示意图

整体来看,共创建了三条样条曲线,对Lux-Nit-Backlight进行映射。和8.1不同的是,并非直接由Lux和Baclight映射,而是将Nit作为Lux和Backlight的中间介质。

  1. mNitsToBacklightSpline
  2. mBacklightToNitsSpline
  3. mBrightnessSpline

曲线

流程:

流程


构造函数开始创建

在上面DisplayPowerController构造函数中会调用以下函数:mBrightnessMapper = BrightnessMappingStrategy.create(resources);

而BrightnessMappingStrategy.java的create函数中获取配置文件config.xml中的配置值(厂商会覆盖重新配置,一般路径会有overlay),然后根据这个配置值决定映射方式:

  • config_autoBrightnessLevels:环境光lux值,等级和背光对应
  • config_autoBrightnessLcdBacklightValues:背光等级
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- Lux值数组-->
<integer-array name="config_autoBrightnessLevels">
</integer-array>
<!-- Lux值对应的背光值数组 -->
<integer-array name="config_autoBrightnessLcdBacklightValues">
</integer-array>

<!-- ##### 以下三组是Android Q之后添加 -->
<!-- Lux值对应的Nits值数组 -->
<array name="config_autoBrightnessDisplayValuesNits">
</array>
<!-- 描述屏幕发光强度的Nits值数组 -->
<array name="config_screenBrightnessNits">
</array>
<!-- 和发光强度Nits值对应的背光值数组 -->
<integer-array name="config_screenBrightnessBacklight">
</integer-array>

创建函数:

frameworks/base/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
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
@Nullable
public static BrightnessMappingStrategy create(Resources resources) {
//lux环境光数组
float[] luxLevels = getLuxLevels(resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevels));
//Lux值对应的背光值
int[] brightnessLevelsBacklight = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
//和Lux值对应的屏幕亮度的Nits值数组,长度比Lux值数组大1。如果配置了该值,则:
//1.config_screenBrightnessNits必须配置
//2.config_screenBrightnessBacklight必须配置
float[] brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
//用户可调整的gamma最大值
float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
1, 1);
//描述屏幕亮度的nits值数组
float[] nitsRange = getFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits));
//与nitsRange数组中的亮度值(单位为Nits)相对应的屏幕背光值
int[] backlightRange = resources.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight);
long shortTermModelTimeout = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
//判断是否是有效映射:
//1.非空
//2.长度相同
//3.元素>=0;4.nitsRange/luxLevels必须递增,backlightRange/brightnessLevelsNits必须非递减
if (isValidMapping(nitsRange, backlightRange)
&& isValidMapping(luxLevels, brightnessLevelsNits)) {
//最小背光值1
int minimumBacklight = resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
//最大背光值255
int maximumBacklight = resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
//创建BrightnessConfiguration.Builder实例对象
//将luxLevels和nits值保存进去
BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
luxLevels, brightnessLevelsNits);
builder.setShortTermModelTimeoutMillis(shortTermModelTimeout);
builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
//(1) 映射Lux值和Nits值,而非Lux值和直接显示的背光值,物理映射
//一般执行该流程创建曲线
return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
autoBrightnessAdjustmentMaxGamma);
} else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
//(2) 直接映射Lux值和背光值,简单映射
return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout);
} else {
return null;
}
}

(1) PhysicalMappingStrategy构造函数

一般执行此处流程:

BrightnessMappingStrategy.java
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
//===================
//(1) PhysicalMappingStrategy构造函数,创建两条映射曲线
@VisibleForTesting
static class PhysicalMappingStrategy extends BrightnessMappingStrategy {
....
public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
int[] backlight, float maxGamma) {
.....
mMaxGamma = maxGamma;
//自动亮度调节
mAutoBrightnessAdjustment = 0;
//自动亮度开启的情况下,用户手动调节亮度时的当前lux值
mUserLux = -1;
//自动亮度开启的情况下,用户手动调节亮度设置的亮度值
mUserBrightness = -1;

// Setup the backlight spline
final int N = nits.length;
float[] normalizedBacklight = new float[N];
for (int i = 0; i < N; i++) {
normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]);
}
//创建Nits-Backlight样条曲线
mNitsToBacklightSpline = Spline.createSpline(nits, normalizedBacklight);
//创建Backlight-Nits样条曲线
mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits);

mDefaultConfig = config;
if (mLoggingEnabled) {
PLOG.start("physical mapping strategy");
}
mConfig = config;
//根据不同的场景创建Lux-nits样条曲线
computeSpline();
}
}

(1.1) PhysicalMappingStrategy中的computeSpline

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
    private void computeSpline() {
//获取BrightnessConfiguration中的Lux数组和Lux值对应的Nits数组,并放入Pair对象中
Pair<float[], float[]> defaultCurve = mConfig.getCurve();
float[] defaultLux = defaultCurve.first; //lux数组
float[] defaultNits = defaultCurve.second; //和lux对应的nits数组
//创建一个和defaultNits等长的数组,用于存放对应的背光值(从曲线中获取)
float[] defaultBacklight = new float[defaultNits.length];
for (int i = 0; i < defaultBacklight.length; i++) {
//从mNitsToBacklightSpline中获取背光值,即根据config_autoBrightnessDisplayValuesNits值
//从config_screenBrightnessNits与config_screenBrightnessBacklight的曲线中获取默认的背光值
defaultBacklight[i] = mNitsToBacklightSpline.interpolate(defaultNits[i]);
}
//对上面获取的背光值进一步加工,如果用户设置过亮度,需将该亮度也加入曲线,
//最终得到调整后的lux数组和brightness数组
Pair<float[], float[]> curve = getAdjustedCurve(defaultLux, defaultBacklight, mUserLux,
mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma);
//最终的lux数组和backlight数组
float[] lux = curve.first;
float[] backlight = curve.second;
float[] nits = new float[backlight.length];
//根据背光值,从config_screenBrightnessNits和onfig_screenBrightnessBacklight构建的mBacklightToNitsSpline曲线中获取Nit值
for (int i = 0; i < nits.length; i++) {
nits[i] = mBacklightToNitsSpline.interpolate(backlight[i]);
}
//完成创建Lux-nits样条曲线
//最终的背光值从此曲线和mNitsToBacklightSpline曲线中获取
mBrightnessSpline = Spline.createSpline(lux, nits);
}

public Pair<float[], float[]> getCurve() {
return Pair.create(Arrays.copyOf(mLux, mLux.length), Arrays.copyOf(mNits, mNits.length));
}

Pair容器类

Pair对两个对象组成的元素组进行传递。这个对象提供了一个合理的equals()方法,如果两个对象的first和second值相等则返回true

特征:

  1. Pair(F first, S second),一个Pair容器里面有2个元素,他们成组存在。
  2. Pair里面两个元素都是final的
  3. Pair的equals是值比较,不是地址比较

示例:

1
2
3
4
5
String PAIR = "PAIR";
Pair p1 = new Pair(18, "张三"); // 通过 构造函数 实例化对象
Pair p2 = Pair.create(20, "李四");//通过 create方法 实例化对象
boolean e1 = p1.equals(p2);
Log.d(PAIR, "RESULT: " + e1); // false

(2) SimpleMappingStrategy构造函数

BrightnessMappingStrategy.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//===================
//(2) 调用SimpleMappingStrategy构造函数
private SimpleMappingStrategy(float[] lux, int[] brightness, float maxGamma,
long timeout) {
final int N = brightness.length;
mLux = new float[N];
mBrightness = new float[N];
for (int i = 0; i < N; i++) {
mLux[i] = lux[i];
mBrightness[i] = normalizeAbsoluteBrightness(brightness[i]);
}

mMaxGamma = maxGamma;
mAutoBrightnessAdjustment = 0;
mUserLux = -1;
mUserBrightness = -1;
//映射lux和brightness曲线
computeSpline();
mShortTermModelTimeout = timeout;
}

(2.1) SimpleMappingStrategy中的computeSpline

BrightnessMappingStrategy.java
1
2
3
4
5
6
7
private void computeSpline() {
//计算调整,得到调整后的Lux值数组和backlight值数组
Pair<float[], float[]> curve = getAdjustedCurve(mLux, mBrightness, mUserLux,
mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma);
//Lux-Nits曲线,最终的背光值从此曲线+mNitsToBacklightSpline曲线获取
mSpline = Spline.createSpline(curve.first, curve.second);
}

AutomaticBrightnessController初始化

在DisplayPowerController构造函数中创建了AutomaticBrightnessController对象

frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
....
mBrightnessMapper = BrightnessMappingStrategy.create(resources);
//背光曲线不为空
if (mBrightnessMapper != null) {
//实例化
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
screenBrightnessThresholds, context, displayDeviceConfig);
} else {
mUseSoftwareAutoBrightnessConfig = false;
}
....

*configure方法配置AutomaticBrightnessController

  1. updatePowerState()中也会对mAutomaticBrightnessController对象进行配置:
DisplayPowerController.java
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
    private void updatePowerState() {
.......
// If the brightness is already set then it's been overridden by something other than the
// user, or is a temporary adjustment.
boolean userInitiatedChange = (Float.isNaN(brightnessState))
&& (autoBrightnessAdjustmentChanged || userSetBrightnessChanged);
boolean hadUserBrightnessPoint = false;
// Configure auto-brightness.
if (mAutomaticBrightnessController != null) {
//曲线中是否有用户设置的短期点
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mBrightnessConfiguration,
mLastUserSetScreenBrightness,
userSetBrightnessChanged, autoBrightnessAdjustment,
autoBrightnessAdjustmentChanged, mPowerRequest.policy);
}
....
}

//表示是否在自动背光打开的情况下拖动亮度条调节过亮度
//判断依据是BrightnessMappingStrategy中的mUserLux成员,它表示用户在开启自动背光后手动设置亮度时的Lux值
@Override
public boolean hasUserDataPoints() {
return mUserLux != -1;
}

配置的参数:

  • autoBrightnessEnabled:表示自动背光是否可用
1
2
3
4
5
6
7
final boolean autoBrightnessEnabledInDoze =
mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
//打开了自动亮度调节&&(亮屏或Doze)&&局部变量brightness为0&&BrightnessMappingStrategy不为空
final boolean autoBrightnessEnabled = mPowerRequest.useAutoBrightness
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
&& Float.isNaN(brightnessState)
&& mAutomaticBrightnessController != null;
  • mBrightnessConfiguration:BrightnessConfiguration对象,携带有用于创建曲线的Lux值数组和对应的Nit值数组。每一个用户可对应一个BrightnessConfiguration,由DisplayManagerService设置
  • userSetBrightnessChanged:用户是否手动通过拖动亮度条设置过亮度
  • autoBrightnessAdjustmentChanged:自动背光调整至adjustment是否发生变化(对应的即下面configure中的userChangedAutoBrightnessAdjustment
  • displayPolicy:当前请求的屏幕状态

  1. 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
30
31
32
public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
float brightness, boolean userChangedBrightness, float adjustment,
boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
//是否要进入Doze状态
boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
//step 1: 设置BrightnessConfiguration对象,若发生变化返回true
boolean changed = setBrightnessConfiguration(configuration);
//step 2: 设置Display状态,若发生变化返回true
changed |= setDisplayPolicy(displayPolicy);
//step 3: 如果用户改变自动背光调节值,设置自动背光调节值
if (userChangedAutoBrightnessAdjustment) {
changed |= setAutoBrightnessAdjustment(adjustment);
}
//step 4: 如果在自动亮度开启的情况下调节了亮度,需要将当前的Lux值和用户设置的亮度添加到曲线中
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) {
//step 5
prepareBrightnessAdjustmentSample();
}
//step 6: 注册LightSensor
changed |= setLightSensorEnabled(enable && !dozing);
//step 7: 如果changed为true,更新自动背光亮度值,但不会主动调用DPC更新背光
if (changed) {
updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange);
}
}

1. setBrightnessConfiguration

  1. 针对每个用户,都会有一个BrightnessConfiguration和它映射,所以当切换用户后,设备的背光将可能发生改变
  2. 当BrightnessConfiguration发生改变且在BrighnessMappingStragety中设置完成后,将会通过resetShortTermModel()清除原有用户的配置

清除用户设置的亮度和对应Lux的三种情况:

  1. 切换用户:handleSettingsChange
  2. BrightnessConfigure对象发生变化:setBrightnessConfiguration
  3. 屏幕进入不可交互状态超过30s,且再次进入交互状态后环境光发生变化:setDisplayPolicy
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
//display/AutomaticBrightnessController.java
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
//Step 1
if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
//Step 2
resetShortTermModel();
return true;
}
return false;
}

public void resetShortTermModel() {
//清楚用户添加的曲线Points
mBrightnessMapper.clearUserDataPoints();
//表示短期模型仍有效
mShortTermModelValid = true;
mShortTermModelAnchor = -1;
}

//display/BrightnessMappingStrategy.java
@Override
public boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config) {
if (config == null) {
config = mDefaultConfig;
}
if (config.equals(mConfig)) {
return false;
}
if (mLoggingEnabled) {
PLOG.start("brightness configuration");
}
//如果config对象发生改变,则替换后,会调用computeSpline重新创建Lux-Nits曲线
mConfig = config;
computeSpline();
return true;
}

@Override
public void clearUserDataPoints() {
if (mUserLux != -1) {
//重置变量
mAutoBrightnessAdjustment = 0;
mUserLux = -1;
mUserBrightness = -1;
//重新创建曲线
computeSpline();
}
}

2. setDisplayPolicy

该方法主要根据屏幕状态来设置mShortTermModelValid的值

当屏幕状态进入Doze或者Asleep后,会发送一个定义Handler,并在到达时间后将mShortTermModelValid值置为false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//display/AutomaticBrightnessController.java
private boolean setDisplayPolicy(int policy) {
if (mDisplayPolicy == policy) {
return false;
}
final int oldPolicy = mDisplayPolicy;
mDisplayPolicy = policy;
//如果Display状态值由交互变为不可交互状态
if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
//发送一个30s的延迟消息,30s后将mShortTermModelValid置为false
mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
mBrightnessMapper.getShortTermModelTimeout());
//如果Display状态值由不可交互变为交互状态,移除延时消息的发送
} else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
}
return true;
}

3. setAutoBrightnessAdjustment

用于设置自动背光调整值,前提是自动背光调整值已经发生变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//display/AutomaticBrightnessController.java
private boolean setAutoBrightnessAdjustment(float adjustment) {
return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
}

//display/BrightnessMappingStrategy.java
@Override
public boolean setAutoBrightnessAdjustment(float adjustment) {
//限制,取值范围为[-1,1]
adjustment = MathUtils.constrain(adjustment, -1, 1);
//adjustment未发生变化
if (adjustment == mAutoBrightnessAdjustment) {
return false;
}
if (mLoggingEnabled) {
Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
adjustment);
PLOG.start("auto-brightness adjustment");
}
//adjustment发生变化,则重新创建曲线
mAutoBrightnessAdjustment = adjustment;
computeSpline();
return true;
}

4. setScreenBrightnessByUser

用于将用户拖动亮度条设置的亮度和当时的Lux值添加到用于创建曲线的数组中,并重新创建曲线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//AutomaticBrightnessController.java
//添加用户设置亮度
private boolean setScreenBrightnessByUser(float brightness) {
if (!mAmbientLuxValid) {
// If we don't have a valid ambient lux then we don't have a valid brightness anyway,
// and we can't use this data to add a new control point to the short-term model.
return false;
}
//将当前的Lux值和用户设置的背光值添加到曲线中
mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
//更新设置当前lux值
mShortTermModelValid = true;
mShortTermModelAnchor = mAmbientLux;
return true;
}

5. prepareBrightnessAdjustmentSample

调用configure更新时,做一些标记记录

6. setLightSensorEnabled

用于LightSensor的注册和解除注册,当设备处于亮屏状态且打开自动背光功能时,将注册一个LightSensor,以监听环境光的强度变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//AutomaticBrightnessController.java
private boolean setLightSensorEnabled(boolean enable) {
if (enable) {
if (!mLightSensorEnabled) {
....
registerForegroundAppUpdater();
//注册
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
mCurrentLightSensorRate * 1000, mHandler);
return true;
}
} else if (mLightSensorEnabled) {
.....
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
unregisterForegroundAppUpdater();
//解除
mSensorManager.unregisterListener(mLightSensorListener);
}
return false;
}

7. *updateAutoBrightness自动背光获取

更新自动背光亮度值

从这处流程可以看出自动背光获取的方式:

  1. 首先会根据当前的Lux值,从mBrightnessSpline曲线中寻找对应的Nit值
  2. 然后根据Nit值,从曲线mNitsToBacklightSpline中获取到最终的背光值

其中mBrightnessSpline曲线是由Lux值数组和它对应的Nit值数组创建,mNitsToBacklightSpline是由配置文件中的config_screenBrightnessNits和config_screenBrightnessBacklight创建

具体的创建在computeSline()方法中

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
//AutomaticBrightnessController.java
private void updateAutoBrightness(boolean sendUpdate, boolean isManuallySet) {
if (!mAmbientLuxValid) {
return;
}
//根据lux值从曲线中获取背光值(区间是[0, 1.0]的浮点数)
float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
mForegroundAppCategory);
//得到最终的自动背光值
float newScreenAutoBrightness = clampScreenBrightness(value);

if (!BrightnessSynchronizer.floatEquals(mScreenAutoBrightness,
newScreenAutoBrightness)) {
mScreenAutoBrightness = newScreenAutoBrightness;
mScreenBrighteningThreshold = clampScreenBrightness(
mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
mScreenDarkeningThreshold = clampScreenBrightness(
mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
//背光更新
if (sendUpdate) {
mCallbacks.updateBrightness();
}
}
}

//BrightnessMappingStrategy.java
@Override
public float getBrightness(float lux, String packageName,
@ApplicationInfo.Category int category) {
//根据lux从曲线中获取nits,然后获取背光
float nits = mBrightnessSpline.interpolate(lux);
float backlight = mNitsToBacklightSpline.interpolate(nits);
...
return backlight;
}

adjustment变量计算

例如dump我的一加六(Android 10)设备,adb shell dumpsys display信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
//开启自动亮度调节后dump
PhysicalMappingStrategy
mConfig=BrightnessConfiguration{[(0.0, 2.0487), (1.0, 4.848), (4.0, 17.2347), (12.0, 39.0867), (20.0, 50.671), (40.0, 92.3019), (65.0, 94.2512), (95.0, 98.372), (140.0, 100.297), (200.0, 105.297), (350.0, 120.385), (650.0, 142.064), (1300.0, 236.5179), (2000.0, 350.0267), (3300.0, 427.6287)], {}, ''}
//背光曲线
mBrightnessSpline=MonotoneCubicSpline{[(0.0, 2.0487: 2.7699974), (1.0, 4.8186975: 3.4543567), (4.0, 17.234846: 3.435018), (12.0, 39.085403: 2.089745), (20.0, 50.67077: 1.7645122), (40.0, 92.28784: 0.23451348), (65.0, 94.25191: 0.023499148), (95.0, 98.38648: 0.09019067), (140.0, 100.30178: 0.0627253), (200.0, 105.275085: 0.0918182), (350.0, 120.38728: 0.08650002), (650.0, 142.0629: 0.108782366), (1300.0, 236.51614: 0.15355834), (2000.0, 349.77896: 0.11084422), (3300.0, 427.6287: 0.05988441)]}
//nits对应背光的曲线
mNitsToBacklightSpline=MonotoneCubicSpline{[(2.0482, 0.0019550342: 0.00395116), (2.543, 0.0039100684: 0.004002362), (3.0253, 0.0058651026: 0.0040531447), (3.5077, 0.007820137: 0.0037272798), (4.0824, 0.009775171: 0.00419204), (4.4748, 0.011730205: 0.005721517), (5.08, 0.015640274: 0.004685791), (6.4233, 0.019550342: 0.002632065), (8.0848, 0.02346041: 0.0017233933), (11.6607, 0.027370479: 0.001788805), (13.2347, 0.031280547: 0.0023087142), (15.0676, 0.035190616: 0.0021758107), (16.8302, 0.039100684: 0.0023342122), (18.4261, 0.043010753: 0.002262629), (20.3103, 0.04692082: 0.0022641667), (21.9042, 0.05083089: 0.00241765), (23.5456, 0.054740958: 0.00236309), (25.2137, 0.058651026: 0.0021678535), (27.1769, 0.062561095: 0.0020940518), (28.9571, 0.06647117: 0.0023456002), (30.5244, 0.07038123: 0.0023162398), (32.3535, 0.074291304: 0.0021968414), (34.0867, 0.07820137: 0.0023086662), (42.366, 0.097751714: 0.0022959393), (51.1309, 0.11730205: 0.0022804863), (59.52, 0.1368524: 0.0023538377), (67.744, 0.15640274: 0.002376392), (75.9738, 0.17595308: 0.002316629), (84.6332, 0.19550343: 0.002155731), (94.1525, 0.21505377: 0.002238446), (102.2207, 0.2346041: 0.0023939852), (110.4878, 0.25415444: 0.0026741978), (117.0405, 0.2737048: 0.0028248527), (124.3733, 0.29325512: 0.0028097979), (130.9928, 0.31280547: 0.00251312), (140.4247, 0.33235583: 0.0021358524), (149.3156, 0.35190615: 0.0023393487), (157.1995, 0.3714565: 0.0024370078), (165.3651, 0.39100686: 0.0024333047), (173.2726, 0.41055718: 0.0024349196), (181.4272, 0.43010753: 0.0024660935), (189.1402, 0.44965786: 0.0024320162), (197.5334, 0.4692082: 0.0023719585), (205.6301, 0.48875856: 0.002383901), (213.9381, 0.5083089: 0.002348846), (222.2769, 0.5278592: 0.002423523), (230.0891, 0.5474096: 0.002398687), (238.6084, 0.5669599: 0.002379861), (246.5399, 0.58651024: 0.0023049354), (255.6544, 0.6060606: 0.0022993367), (263.6221, 0.62561095: 0.002403119), (271.9324, 0.6451613: 0.002531584), (279.1449, 0.66471165: 0.0023920578), (288.5736, 0.684262: 0.002112214), (297.6628, 0.7038123: 0.0022218374), (306.1899, 0.7233627: 0.0023296294), (314.4511, 0.742913: 0.0024545297), (322.1404, 0.76246333: 0.002378489), (330.969, 0.7820137: 0.002454385), (338.2251, 0.80156404: 0.0025690594), (346.2251, 0.82111436: 0.0023937116), (354.567, 0.8406647: 0.0017740328), (370.799, 0.86021507: 2.6955837E-4), (413.1738, 0.8797654: 0.0013575983), (415.6397, 0.8993157: 0.009982219), (417.264, 0.9188661: 0.010905683), (419.264, 0.9384164: 0.009775162), (421.264, 0.95796674: 0.007777949), (424.646, 0.9775171: 0.0066592516), (427.6287, 1.0: 0.0075377673)]}

mMaxGamma=3.0
mAutoBrightnessAdjustment=0.0
mUserLux=-1.0
mUserBrightness=-1.0
mDefaultConfig=BrightnessConfiguration{[(0.0, 2.0487), (1.0, 4.848), (4.0, 17.2347), (12.0, 39.0867), (20.0, 50.671), (40.0, 92.3019), (65.0, 94.2512), (95.0, 98.372), (140.0, 100.297), (200.0, 105.297), (350.0, 120.385), (650.0, 142.064), (1300.0, 236.5179), (2000.0, 350.0267), (3300.0, 427.6287)], {}, ''}

用户手动调节亮度条

入参adjustment,范围是[-1.0, 1.0]

DisplayManager的setTemporaryAutoBrightnessAdjustment接口供上层应用调用,作为入口

1
2
3
4
5
6
7
8
9
10
11
frameworks/base/core/java/android/hardware/display/DisplayManager.java - setTemporaryAutoBrightnessAdjustment  ---->
frameworks/base/core/java/android/hardware/display/DisplayManagerGlobal.java - setTemporaryAutoBrightnessAdjustment [入参adjustment] ---->
IDisplayManager.aidl - setTemporaryAutoBrightnessAdjustment [AIDL跨进程] ---->
DisplayManagerService.java - setTemporaryAutoBrightnessAdjustment [Binder call] --->
DisplayPowerController.java - setTemporaryAutoBrightnessAdjustment [消息处理] ----->
updatePowerState ---->
(1) updateUserSetScreenBrightness [mLastUserSetScreenBrightness更新值,并返回true赋值给userSetBrightnessChanged] 详细代码参考上面小节
(2) AutomaticBrightnessController.configure [会入参上面两个变量:mLastUserSetScreenBrightness和userSetBrightnessChanged] ---->
setScreenBrightnessByUser ---->
BrightnessMappingStrategy.java - addUserDataPoint ---->
getUnadjustedBrightness

大致流程:
流程

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//DisplayPowerController.java - updatePowerState
...
if (mAutomaticBrightnessController != null) {
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mBrightnessConfiguration,
mLastUserSetScreenBrightness,
userSetBrightnessChanged, autoBrightnessAdjustment,
autoBrightnessAdjustmentChanged, mPowerRequest.policy);
}
//============================
//AutomaticBrightnessController.java
//mLastUserSetScreenBrightness对应brightness
//userSetBrightnessChanged对应userChangedBrightness
//autoBrightnessAdjustment对应adjustment
public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
float brightness, boolean userChangedBrightness, float adjustment,
boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
....
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);
}
....
//============================
//BrightnessMappingStrategy.java
//brightness即上面传参的用户手动设置的背光mLastUserSetScreenBrightness
@Override
public void addUserDataPoint(float lux, float brightness) {
//step 1: 获取默认配置值创建的曲线中Lux值对应的背光值
float unadjustedBrightness = getUnadjustedBrightness(lux);
//step 2: 通过传入的三个值计算调整 自动背光值
float adjustment = inferAutoBrightnessAdjustment(mMaxGamma,
brightness /* desiredBrightness */,
unadjustedBrightness /* currentBrightness */);
//更新自动背光调整值(浮点)
mAutoBrightnessAdjustment = adjustment;
//表示用户在开启自动背光情况下拖动亮度条调节亮度时的当时Lux值
mUserLux = lux;
//表示用户在开启自动背光情况下拖动亮度条调节亮度值
mUserBrightness = brightness;
//step 3: 更新曲线图
computeSpline();
}
//step 1 获取曲线中的对应背光值
private float getUnadjustedBrightness(float lux) {
//获取BrightnessConfiguration中的Lux-Nits映射
Pair<float[], float[]> curve = mConfig.getCurve();
//创建一个lux-nits样条曲线
Spline spline = Spline.createSpline(curve.first, curve.second);
//根据lux得到nits值,再根据nit值从mNitsToBacklightSpline中的到对应的背光 0-1的float浮点数
return mNitsToBacklightSpline.interpolate(spline.interpolate(lux));
}

//step 2 推断adjustment值
protected float inferAutoBrightnessAdjustment(float maxGamma, float desiredBrightness,
float currentBrightness) {
float adjustment = 0;
float gamma = Float.NaN;
// 当前Lux值对应的默认配置亮度值 <=25.5 || >= 229.5 (0-255默认背光)
if (currentBrightness <= 0.1f || currentBrightness >= 0.9f) {
adjustment = (desiredBrightness - currentBrightness);
//最暗的可能情况
} else if (desiredBrightness == 0) {
adjustment = -1;
//最大亮度255
} else if (desiredBrightness == 1) {
adjustment = +1;
} else {
// current^gamma = desired => gamma = log[current](desired)
//根据换底公式,得到currentBrightness为底desiredBrightness的对数
gamma = MathUtils.log(desiredBrightness) / MathUtils.log(currentBrightness);
// max^-adjustment = gamma => adjustment = -log[max](gamma)
//maxGamma为底gamma的对数
adjustment = -MathUtils.log(gamma) / MathUtils.log(maxGamma);
}
adjustment = MathUtils.constrain(adjustment, -1, +1);
//返回计算后的adjustment
return adjustment;
}

//step 3 在computeSpline方法重新创建样条曲线的时候,会调用getAdjustedCurve函数
protected Pair<float[], float[]> getAdjustedCurve(float[] lux, float[] brightness,
float userLux, float userBrightness, float adjustment, float maxGamma) {
float[] newLux = lux;
float[] newBrightness = Arrays.copyOf(brightness, brightness.length);
//限定取值范围
adjustment = MathUtils.constrain(adjustment, -1, 1);
//maxGamma 的 -adjustment次方得到gamma值
float gamma = MathUtils.pow(maxGamma, -adjustment);
//gamma != 1说明adjustment不为0
if (gamma != 1) {
for (int i = 0; i < newBrightness.length; i++) {
//重新设置亮度值,新的亮度值为就亮度值的gamma次方
newBrightness[i] = MathUtils.pow(newBrightness[i], gamma);
}
}
//用户在BrightnessController拖动条上手动调节了亮度
if (userLux != -1) {
//插入一对新的lux和对应背光值
Pair<float[], float[]> curve = insertControlPoint(newLux, newBrightness, userLux,
userBrightness);
newLux = curve.first;
newBrightness = curve.second;
if (mLoggingEnabled) {
// This is done for comparison.
curve = insertControlPoint(lux, brightness, userLux, userBrightness);
}
}
//返回该Pair对象给到computeSpline()中
return Pair.create(newLux, newBrightness);
}

private Pair<float[], float[]> insertControlPoint(
float[] luxLevels, float[] brightnessLevels, float lux, float brightness) {
//找到插入点索引,以保持值的递增
final int idx = findInsertionPoint(luxLevels, lux);
final float[] newLuxLevels;
final float[] newBrightnessLevels;
//1. 插入索引等于数组长度
if (idx == luxLevels.length) {
//需要插入到末尾位置,且新Lux数组长度比原来大1
newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length + 1);
newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length + 1);
newLuxLevels[idx] = lux;
newBrightnessLevels[idx] = brightness;
//2. 用户lux值已处在lux值数组中
} else if (luxLevels[idx] == lux) {
newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length);
newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length);
newBrightnessLevels[idx] = brightness;
} else {
//初始化新的lux数组,长度比原数组大1
newLuxLevels = Arrays.copyOf(luxLevels, luxLevels.length + 1);
//将原数组从idx位置起的元素,向后移动1位,将新的Lux值插入到idx位置
System.arraycopy(newLuxLevels, idx, newLuxLevels, idx+1, luxLevels.length - idx);
newLuxLevels[idx] = lux;
//初始化新亮度值数组,长度比原数组大1
newBrightnessLevels = Arrays.copyOf(brightnessLevels, brightnessLevels.length + 1);
//原数组从idx位置起的元素,向后移动1位,将新的亮度值值插入到idx位置
System.arraycopy(newBrightnessLevels, idx, newBrightnessLevels, idx+1,
brightnessLevels.length - idx);
newBrightnessLevels[idx] = brightness;
}
//平滑曲线
//newLuxLevels之后的Lux对应的亮度值将全部为newBrightnessLevels
smoothCurve(newLuxLevels, newBrightnessLevels, idx);
//返回一个携带有Lux和背光值的Pair对象给getAdjustedCurve()
return Pair.create(newLuxLevels, newBrightnessLevels);
}
//返回arr数组(递增)中开始大于等于val值的 数组下标
private int findInsertionPoint(float[] arr, float val) {
for (int i = 0; i < arr.length; i++) {
if (val <= arr[i]) {
return i;
}
}
return arr.length;
}

debug调试

  1. dump power:执行命令adb shell dumpsys power|grep "Brightness"查看背光相关
  2. 抓取log查看上层背光变化,背光节点,以及kernel中背光变化
  3. 在DisplayPowerController.java中将Debug log开关打开
  4. 使用dump查看自动亮度调节的变量值: adb shell dumpsys display

参考

Android R AOSP源码Opensys

详解Android中AsyncTask的使用

深入理解AsyncTask的工作原理

Android Message和obtainMessage的区别

Handler的sendMessage和obtainMessage和sendToTarget比较

Android7.1 亮度自动调节

*Android 9.0 自动背光机制分析

本文作者 : sunwengang
本文使用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议
本文链接 : https://alonealive.github.io/Blog/2021/05/07/2021/210507_android_brightness/

本文最后更新于 天前,文中所描述的信息可能已发生改变