Android 11 自动亮度调试流程

本文详细介绍了Android系统中自动背光调节的工作原理,包括监听lightsensor数据,根据Lux值计算亮度,以及使用BrightnessMappingStrategy创建映射曲线。通过PhysicalMappingStrategy构建Lux-Nits-Backlight的映射关系,实现精确的亮度控制。此外,还分析了AutomaticBrightnessController的角色及其配置过程,展示了如何根据用户输入调整亮度曲线。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

⾃动背光调节主要过程是通过:监听light sensor 数据,得到对应的 Lux 值,再通过配置的背光曲线计算出当前的亮度,然后设置亮度值。

Settings.System.putInt(mContext.getContentResolver(), SCREEN_BRIGHTNESS_MODE,(isAuto ? 1 : 0) );//把设置的值写入

DisplayManagerService.java
   @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) {
                        // The order of operations 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,
                        mDisplayDevices.get(Display.DEFAULT_DISPLAY));
                mSensorManager = sensorManager;
            }

            mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
        }
DisplayPowerController.java

    public DisplayPowerController(Context context,
                                  DisplayPowerCallbacks callbacks, Handler handler,
                                  SensorManager sensorManager, DisplayBlanker blanker) {
				//……
        if (mUseSoftwareAutoBrightnessConfig) {
			//……
			//获取映射Lux-Nits-Backlight值的对象
            mBrightnessMapper = BrightnessMappingStrategy.create(resources);
            if (mBrightnessMapper != null) {
			//实例化⾃动背光控制器
                mAutomaticBrightnessController = new AutomaticBrightnessController(this,
                        handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
                        lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
                        mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                        initialLightSensorRate, brighteningLightDebounce, darkeningLightDebo
                        autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThreshold
                        screenBrightnessThresholds, shortTermModelTimeout,
                        context.getPackageManager());
            } else {
                mUseSoftwareAutoBrightnessConfig = false;
            }
        }
		//……
    }

BrightnessMappingStrategy
我们从BrightnessMappingStrategy.create(resources)进入,来查看曲线的绘制,create()方法如下,
   @Nullable
 public static BrightnessMappingStrategy create(Resources resources) {
    //Lux值的数组,getLuxLevels()中会将Lux[0] = 0.
    float[] luxLevels = getLuxLevels(resources.getIntArray(
            com.android.internal.R.array.config_autoBrightnessLevels));
    //Lux值对应的背光值,9.0中将不会使用他
    int[] brightnessLevelsBacklight = resources.getIntArray(
            com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
    //描述和Lux值对应的屏幕亮度的Nits值数组,长度比Lux值数组大1。如果配置了该值,则:
    // ---config_screenBrightnessNits必须配置
    // ---config_screenBrightnessBacklight必须配置
    float[] brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
            com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
    //用户可调整的最大Gama值
    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);
    //判断是否是有效映射:1.非空;2.长度相同;3.元素>=0;4.nitsRange/luxLevels必须递增,backlightRange/brightnessLevelsNits必须非递减
    if (isValidMapping(nitsRange, backlightRange)
            && isValidMapping(luxLevels, brightnessLevelsNits)) {
        //最小背光值6
        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实例
        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
        //将读取的Lux值和nits值保存在builder对象中
        builder.setCurve(luxLevels, brightnessLevelsNits);
        //映射Lux值和Nits值,而非Lux值和直接显示的背光值,物理映射
        return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
                autoBrightnessAdjustmentMaxGamma);
    } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
        //直接映射Lux值和背光值,简单映射
        return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
                autoBrightnessAdjustmentMaxGamma);
    } else {
        return null;
    }
}
在create()方法中,首先读取config.xml文件中的配置值,然后根据这个配置值决定映射方式。
在9.0之前,自动背光只需配置Lux值和对应的Backlight值来创建简单的映射,在9.0中,摒弃了这种方式,额外增加了三个配置值,并根据这些配置值决定是使用物理映射还是简单映射,涉及到的配置值如下:

<!-- Lux值数组-->
<integer-array name="config_autoBrightnessLevels">
</integer-array>
<!-- Lux值对应的背光值数组 -->
<integer-array name="config_autoBrightnessLevels">
</integer-array>
<!-- Lux值对应的Nits值数组 -->
<array name="config_autoBrightnessDisplayValuesNits">
</array>
<!-- 描述屏幕发光强度的Nits值数组 -->
<array name="config_screenBrightnessNits">
</array>
<!-- 和发光强度Nits值对应的背光值数组 -->
<integer-array name="config_screenBrightnessBacklight">
</integer-array>


config_autoBrightnessLevels将不再使用。

BrightnessConfiguration表示亮度的配置类,其中保存了Lux值数组和Lux值对应的Nits值数组:
private BrightnessConfiguration(float[] lux, float[] nits, String description) {
    mLux = lux;
    mNits = nits;
    mDescription = description;
}


提供了一个getCurve()接口,用于提供它的mLux和mNits。
接下来进入到物理映射关系对象PhysicalMappingStrategy的创建,看其构造方法:

/**
 * @param config BrightnessConfiguration对象,携带有用于创建曲线的Lux数组和对应的Nits数组
 * @param nits 描述屏幕发光强度的nits值数组
 * @param backlight 描述与nits值数组对应的背光值
 * @param maxGamma 用户可调整最大Gama值
 */
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];
    //将背光值/255后,存储在normalizedBacklight数组中
    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;
    mConfig = config;
    //将根据不同的场景,创建Lux-Nits样条曲线
    computeSpline();
}

PhysicalMappingStrategy

/**
 * @param config BrightnessConfiguration对象,携带有用于创建曲线的Lux数组和对应的Nits数组
 * @param nits 描述屏幕发光强度的nits值数组
 * @param backlight 描述与nits值数组对应的背光值
 * @param maxGamma 用户可调整最大Gama值
 */
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];
    //将背光值/255后,存储在normalizedBacklight数组中
    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;
    mConfig = config;
    //将根据不同的场景,创建Lux-Nits样条曲线
    computeSpline();
}
在PhysicalMappingStrategy的构造方法中,首先根据config_screenBrightnessNits数组和config_screenBrightnessBacklight数组,创建了两条映射曲线,然后调用computeSpline()方法。
computeSpline()是很重要的一个方法,这个方法中除了创建另外一条Lux-Nits曲线外,还会根据用户当前对亮度的调整,插入用户调整后的值,并调整Lux-Nits曲线

private void computeSpline() {
    //得到BrightnessConfiguration中的Lux数组和Lux值对应的Nits数组,并放入Pair对象中
    Pair<float[], float[]> defaultCurve = mConfig.getCurve();
    //Lux数组
    float[] defaultLux = defaultCurve.first;
    //和Lux数组映射的Nits数组
    float[] defaultNits = defaultCurve.second;
    //创建一个和defaultNits数组等长的数组,用来存放对应的背光值,从Nits-backlights曲线中获取
    //根据Lux-Nit值,从NitsToBacklight曲线中获取背光值
    //即根据config_autoBrightnessDisplayValuesNits值从config_screenBrightnessNits与config_screenBrightnessBacklight的曲线中获取默认的背光值
    float[] defaultBacklight = new float[defaultNits.length];
    for (int i = 0; i < defaultBacklight.length; i++) {
        defaultBacklight[i] = mNitsToBacklightSpline.interpolate(defaultNits[i]);
    }
    //对得到的默认背光值进一步加工,如果用户设置过亮度,需要将用户设置的亮度值添加进曲线,得到
    //调整后的Lux值数组和backlight值数组
    Pair<float[], float[]> curve = getAdjustedCurve(defaultLux, defaultBacklight, mUserLux,
            mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma);
    //最终的Lux值和背光值
    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);
}
在这个方法中,首先调用mConfig.getCurve()方法,获取了mConfig对象中的mLux和mNit的拷贝,这两个值就是在创建mConfig时传入的config_autoBrightnessLevels数组和config_autoBrightnessDisplayValuesNits数组。
然后利用得到的nits值从曲线mNitsToBacklightSpline中得到背光值数组defaultBacklight;

接下来,调用getAdjustedCurve()方法对defaultBacklight[]做进一步加工,如果在自动背光打开的情况下,用户没有通过亮度条调节背光,则将返回原数据。此处暂且认为没有操作过亮度条,对getAdjustedCurve()先不做分析。

最后,利用defaultBacklight数组从曲线mBacklightToNitsSpline中得到Nits值,然后,创建表示Lux值和对应Nits值的曲线mBrightnessSpline,这也是创建的最后一条全局样条曲线(在某些方法中会创建一些临时曲线)。


>光照度:从光源照射到单位面积上的光通量,以E表示,照度的单位为勒克斯(Lux,简称lx);
>光亮度:指一个表面的明亮程度,以L表示,即从一个表面反射出来的光通量.不同物体对光有不同的反射系数或吸收系数.光的强度可用照在平面上的光的总量来度量,这叫入射光(inci-dentlight)或照度(illuminance).若用从平面反射到眼
球中的光量来度量光的强度,这种光称为反射光或亮度.例如,一般白纸大约吸收入射光量的20%,反射光量为80%;黑纸只反射入射光量的3%.所以,白纸和黑纸在亮度上差异很大。

因此,从光学角度而言,我们感知的亮度是指从屏幕反射到眼球中的光的强度,而且这个强度跟光亮度(Nit)有一定关系,光亮度又跟光照度(Lux)有一定关系,因此,如果严格考虑光照度、光亮度、入射光、反射光等调节,相比通过Lux值决定
背光值而言,通过Lux值决定Nit值,再由Nit值决定背光值,无疑是最精准的。

还是从DisplayPowerController中开始,对光照强度的采集、获取自动背光都在AutomaticBrightnessController中进行,我们从它的创建和配置分别对它进行分析。
//DisplayPowerController.updatePowerState()中

//获取映射Lux-Nits-Backlight值的对象
mBrightnessMapper = BrightnessMappingStrategy.create(resources);
//初始化AutomaticBrightnessController
if (mBrightnessMapper != null) {
    //实例化自动背光控制器
    mAutomaticBrightnessController = new AutomaticBrightnessController(this,
            handler.getLooper(), sensorManager, mBrightnessMapper,
            lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
            mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
            initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
            autoBrightnessResetAmbientLuxAfterWarmUp, hysteresisLevels);
} else {
    mUseSoftwareAutoBrightnessConfig = false;
}
AutomaticBrightnessController的配置
DisplayPowerController中,每一次调用updatePowerState()更新状态时,都会对AutomaticBrightnessController进行配置:
boolean hadUserBrightnessPoint = false;
// Configure auto-brightness.
if (mAutomaticBrightnessController != null) {
    //曲线中是否有用户设置的短期点
    hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
    //配置mAutomaticBrightnessController
    mAutomaticBrightnessController.configure(autoBrightnessEnabled,
            mBrightnessConfiguration,
            mLastUserSetScreenBrightness / (float) PowerManager.BRIGHTNESS_ON,
            userSetBrightnessChanged, autoBrightnessAdjustment,
            autoBrightnessAdjustmentChanged, mPowerRequest.policy);
}
在以上逻辑中,hadUserBrightnessPoint表示是否在自动背光打开的情况下拖动亮度条调节过亮度,判断依据是BrightnessMappingStrategy中的mUserLux成员,它表示用户在开启自动背光后手动设置亮度时的Lux值:
@Override
public boolean hasUserDataPoints() {
    return mUserLux != -1;
}
然后开始调用configure()方法进行配置,先来看看这些参数:autoBrightnessEnabled:表示自动背光是否可用,由以下值决定
//打开了自动亮度调节&&(亮屏或Doze)&&局部变量brightness为0&&BrightnessMappingStrategy不为空
final boolean autoBrightnessEnabled = mPowerRequest.useAutoBrightness
            && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
            && brightness < 0
            && mAutomaticBrightnessController != null;
 mBrightnessConfiguration:BrightnessConfiguration对象,携带有用于创建曲线的Lux值数组和对应的Nit值数组,每一个用户可对应一个BrightnessConfiguration,由DisplayManagerService负责设置。
 brightness:当前亮度值/255的结果,区间为(0,1.0].
 userChangedBrightness:表示用户是否手动通过拖动亮度条设置过亮度。
 userChangedAutoBrightnessAdjustment:表示自动背光调整值adjustment是否发生变化。
 displayPolicy:当前请求的屏幕状态。
 
 /**
 * @param enable 自动背光功能是否可用
 * @param configuration BrightnessConfiguration对象
 * @param brightness 当前背光值/255的形式
 * @param userChangedBrightness  用户是否改变过背光值
 * @param adjustment 自动背光调节值
 * @param userChangedAutoBrightnessAdjustment 用户是否改变过自动背光调节值
 * @param displayPolicy PMS中要请求的Diplay状态值
 */
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);
    //设置BrightnessConfigure对象,若BrightnessConfigure发生改变,返回true
    boolean changed = setBrightnessConfiguration(configuration);
    //设置Display状态,若发生改变,返回true
    changed |= setDisplayPolicy(displayPolicy);
    //如果用户改变自动背光调节值,设置自动背光调节值
    if (userChangedAutoBrightnessAdjustment) {
        changed |= setAutoBrightnessAdjustment(adjustment);
    }
    //如果在自动亮度开启的情况下调节了亮度,需要将当前的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) {
        //做旧值的记录
        prepareBrightnessAdjustmentSample();
    }
    //注册解除注册LSensor
    changed |= setLightSensorEnabled(enable && !dozing);
    //如果changed为true,更新自动背光亮度值,但不会主动调用DPC更新背光
    if (changed) {
        updateAutoBrightness(false /*sendUpdate*/);
    }
}
setBrightnessConfiguration()
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
    if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
        //如果config对象发生改变,重置用户设置的曲线点
        resetShortTermModel();
        return true;
    }
    return false;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值