Android 8.1 DisplayPowerController(四) 自动调节亮度(1)——流程

作者:FightFightFight 
来源:CSDN 
原文:https://blog.csdn.net/FightFightFight/article/details/83626332 

和手动调节亮度相比,自动调节亮度则稍微复杂些。其中涉及到多个算法。这里先笼统地介绍其流程,对涉及到的算法在下一篇文章中进行学习。

从前面的分析得到,不管是哪种背光调节方式,其最终都会在DisplayPowerController的updatePowerState()方法中进行决策,得到最终的背光值,自动背光的亮度也不例外:

private void updatePowerState() {
    if (brightness < 0) {
        if (autoBrightnessEnabled) {
            //得到自动亮度背光值
            brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
        }
    }
        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
            }
           mAppliedAutoBrightness = true;
        } else {
            mAppliedAutoBrightness = false;
            }
    } else {
        mAppliedAutoBrightness = false;
    }
}

从上面逻辑可以看出,自动调节的亮度值是通过mAutomaticBrightnessController的getAutomaticScreenBrightness()方法得到的,所以,现在开始学习一下mAutomaticBrightnessController是什么,以及mAutomaticBrightnessController中是如何得到自动亮度的。

1.AutoBrightnessController的初始化
AutoBrightnessController是自动调节亮度的控制器,在DisplayManagerService中初始化DisplayPowerController时,就获取了该控制器实例:

/**
 * Creates the display power controller.
 */
public DisplayPowerController(Context context,
        DisplayPowerCallbacks callbacks, Handler handler,
        SensorManager sensorManager, DisplayBlanker blanker) {
    mSensorManager = sensorManager;
    final Resources resources = context.getResources();
    int screenBrightnessRangeMinimum = Math.min(Math.min(
            screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
            mScreenBrightnessDarkConfig);
    mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
            com.android.internal.R.bool.config_automatic_brightness_available);
    int lightSensorRate = resources.getInteger(
            com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
    int initialLightSensorRate = resources.getInteger(
            com.android.internal.R.integer.config_autoBrightnessInitialLightSensorRate);
    if (initialLightSensorRate == -1) {
      initialLightSensorRate = lightSensorRate;
    } else if (initialLightSensorRate > lightSensorRate) {
      Slog.w(TAG, "Expected config_autoBrightnessInitialLightSensorRate ("
              + initialLightSensorRate + ") to be less than or equal to "
              + "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
    }
    long brighteningLightDebounce = resources.getInteger(
            com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
    long darkeningLightDebounce = resources.getInteger(
            com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
    boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
            com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
    int ambientLightHorizon = resources.getInteger(
            com.android.internal.R.integer.config_autoBrightnessAmbientLightHorizon);
    float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
            com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
            1, 1);
    int[] brightLevels = resources.getIntArray(
            com.android.internal.R.array.config_dynamicHysteresisBrightLevels);
    int[] darkLevels = resources.getIntArray(
            com.android.internal.R.array.config_dynamicHysteresisDarkLevels);
    int[] luxLevels = resources.getIntArray(
            com.android.internal.R.array.config_dynamicHysteresisLuxLevels);
    HysteresisLevels dynamicHysteresis = new HysteresisLevels(
            brightLevels, darkLevels, luxLevels);

    if (mUseSoftwareAutoBrightnessConfig) {
        int[] lux = resources.getIntArray(
                com.android.internal.R.array.config_autoBrightnessLevels);
        int[] screenBrightness = resources.getIntArray(
                com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
        int lightSensorWarmUpTimeConfig = resources.getInteger(
                com.android.internal.R.integer.config_lightSensorWarmupTime);
        final float dozeScaleFactor = resources.getFraction(
                com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
                1, 1);
        Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
        if (screenAutoBrightnessSpline == null) {
            Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues ... disabled.");
            mUseSoftwareAutoBrightnessConfig = false;
        } else {
            int bottom = clampAbsoluteBrightness(screenBrightness[0]);
            if (mScreenBrightnessDarkConfig > bottom) {
            }
            if (bottom < screenBrightnessRangeMinimum) {
                screenBrightnessRangeMinimum = bottom;
            }
            //实例化AutomaticBrightnessController
            mAutomaticBrightnessController = new AutomaticBrightnessController(this,
                    handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
                    lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
                    mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                    initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
                    autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
                    autoBrightnessAdjustmentMaxGamma, dynamicHysteresis);

        }
    }
}

在DisplayPowerController的构造方法中,实例化了AutomaticBrightnessController,从以上逻辑中看出,其构造方法参数多达16个,构造方法以及参数如下:


/**
 * @param callbacks AutomaticBrightnessController.Callbacks接口对象,DisplayPowerController实现了该接口
 * @param looper 来自PMS中的Handler的looper;
 * @param sensorManager SensorManager对象
 * @param autoBrightnessSpline 样条插值后的Spline对象
 * @param lightSensorWarmUpTime LightSensor预热时间
 * @param brightnessMin 可以设置的最小亮度值,Math.min(Math.min(Settings,dim),dark)
 * @param brightnessMax 可以设置的最大亮度值,255
 * @param dozeScaleFactor Doze下自动调节亮度的减少比例,100%表示不减少
 * @param lightSensorRate LightSensor事件速率
 * @param initialLightSensorRate 初始LightSensor事件速率,用于在进入sleep后,获得第一个光样例时,-1表示禁用该值
 * @param brighteningLightDebounceConfig 进入明亮环境时的去抖时间
 * @param darkeningLightDebounceConfig 进入黑暗环境时的去抖时间
 * @param resetAmbientLuxAfterWarmUpConfig 是否在预热之后将立即重新计算环境光水平估计,并立即调整屏幕亮度
 * @param ambientLightHorizon 采集光样本的时间范围周期
 * @param autoBrightnessAdjustmentMaxGamma 伽马最大调整范围
 * @param dynamicHysteresis 使用给定的等长数组创建的HysteresisLevels对象
 */
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
        SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
        int brightnessMin, int brightnessMax, float dozeScaleFactor,
        int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
        long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
        int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
        HysteresisLevels dynamicHysteresis) {
    mCallbacks = callbacks;
    mSensorManager = sensorManager;
    mScreenAutoBrightnessSpline = autoBrightnessSpline;
    mScreenBrightnessRangeMinimum = brightnessMin;
    mScreenBrightnessRangeMaximum = brightnessMax;
    mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
    mDozeScaleFactor = dozeScaleFactor;
    mNormalLightSensorRate = lightSensorRate;
    mInitialLightSensorRate = initialLightSensorRate;
    mCurrentLightSensorRate = -1;
    mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
    mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
    mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
    mAmbientLightHorizon = ambientLightHorizon;
    mWeightingIntercept = ambientLightHorizon;
    mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
    mDynamicHysteresis = dynamicHysteresis;

    //创建AutomaticBrightnessHandler实例,使用来自PMS中的Looper
    mHandler = new AutomaticBrightnessHandler(looper);
    //AmbientLightRingBuffer是已存储光照Lux值和对应时间点的环形缓冲区,按时间排序
    //存储所有的时间戳、Lux值
    mAmbientLightRingBuffer =
        new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
    //只存储初始采集光强时间范围的时间戳、Lux值(LSensor开启前10s的)
    mInitialHorizonAmbientLightRingBuffer =
        new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
    //获取LightSensor实例
    if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
        mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    }
}

以上就是AutomaticBrightnessController的初始化流程,其中一些参数含义已在代码中进行了注释。
在初始化完成后,接下来我们来看它的配置。

2.AutomaticBrightnessController的配置
自动背光控制器的配置也是在DisplayPowerController中完成的。回到DisplayPowerController中,对AutomaticBrightnessController有如下配置:

private void updatePowerState() {
    // Configure auto-brightness.
    boolean autoBrightnessEnabled = false;
    //如果mAutomaticBrightnessController 不为空
    if (mAutomaticBrightnessController != null) {
        //是否在doze下自动调节亮度可用
        final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig
            && (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND);
        //是否自动调节亮度可用
        autoBrightnessEnabled = mPowerRequest.useAutoBrightness
            && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
            && brightness < 0;
        //是否自动调节亮度调整值发生变化
        final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
            && mPowerRequest.brightnessSetByUser;
        //配置AutomaticBrightnessController
        mAutomaticBrightnessController.configure(autoBrightnessEnabled,
            mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
            userInitiatedChange);
    }
}

在这里可以看出,每当调用updatePowerState()方法,都会通过调用AutomaticBrightnessController的configure()方法进行相关值的配置。其中参数:

1.autoBrightnessEnabled:表示自动调节亮度是否开启,通过PMS中得到,而PMS中则通过字段Settings.System.SCREEN_BRIGHTNESS_MODE获取Settings数据库中的值;
2.mPowerRequest.screenAutoBrightnessAdjustment:表示自动调节亮度的调整值,这个值是当Settings中打开自动调节亮度后,如果拖动亮度进度条调节亮度,将会改变该值,具体逻辑在BrightnessController中:
private void setBrightnessAdj(float adj) {
    try {
        mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
    } catch (RemoteException ex) {
    }
}

在分析手动调节亮度时也说过,如果自动调节亮度是打开的,那么拖动亮度条时,虽然可以改变亮度,其原理就是由于此值发生改变,从而使得AutomaticBrightnessController的得到的亮度值发生了改变。

3.userInitiatedChange:表示自动调节亮度的调整值是否发生过改变,简而言之,表示是否在自动调节亮度打开的情况下拖动亮度条。
现在进入configure()方法中,该方法如下:

/**
 * @param enable 自动亮度调节是否可用
 * @param adjustment 自动亮度调节调整值
 * @param dozing 屏幕是否处于Doze状态下
 * @param userInitiatedChange 自动亮度调节调整值是否发生变化
 */
public void configure(boolean enable, float adjustment, boolean dozing,
        boolean userInitiatedChange) {
    mDozing = dozing;
    //注册/解除注册LightSensor,即开启自动调节亮度且非Doze状态下才可用
    boolean changed = setLightSensorEnabled(enable && !dozing);
    //如果自动背光调整值发生变化
    if (enable && !dozing && userInitiatedChange) {
        prepareBrightnessAdjustmentSample();
    }
    //设置调整值
    changed |= setScreenAutoBrightnessAdjustment(adjustment);
    //changed为true则说明自动调节亮度状态发生改变或自动亮度调整值发生改变,则更新亮度
    if (changed) {
        updateAutoBrightness(false /*sendUpdate*/);
    }
}

利用这个方法,将一步步地撬开AutomaticBrightnessController的大门。在configure()方法中,调用了四个方法,这些方法放在此处分析比较凌乱,因此在下面对configure()方法拆分一一进行分析。

2.1.注册LightSensor
注册LightSensor方法如下:

private boolean setLightSensorEnabled(boolean enable) {
    if (enable) {
        if (!mLightSensorEnabled) {
            //表示LightSensor可用
            mLightSensorEnabled = true;
           //LSensor开始时间
            mLightSensorEnableTime = SystemClock.uptimeMillis();
           //当前LSensor事件率
            mCurrentLightSensorRate = mInitialLightSensorRate;
            mSensorManager.registerListener(mLightSensorListener, mLightSensor,
                    mCurrentLightSensorRate * 1000, mHandler);
            return true;
        }
    } else {
        if (mLightSensorEnabled) {
           //表示LightSensor不可用
            mLightSensorEnabled = false;
            //是否需要在点亮屏幕后立即调整亮度
            mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
           //环形缓冲区中最近收集的光照样例的数量
            mRecentLightSamples = 0;
            //清除环形缓冲区
            mAmbientLightRingBuffer.clear();
            mInitialHorizonAmbientLightRingBuffer.clear();
           //当前LSensor事件速率置为-1
            mCurrentLightSensorRate = -1;
            //移除更新Lux值的handler
            mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
            mSensorManager.unregisterListener(mLightSensorListener);
        }
    }
    return false;
}

在上述方法中,根据参数对LightSensor进行了注册和解除注册并返回true或false。
这个方法比较简单,其中有个成员变量需要注意——mAmbientLuxValid,它表示mAmbientLux变量是否持有一个有效参数,在解除L-Sensor时,mAmbientLuxValid的值由mResetAmbientLuxAfterWarmUpConfig值取反得到,后者在构造方法中初始化,如果为true,则表示在屏幕打开后,自动背光控制器将尝试根据当前传感器读数调整亮度;如果为false,控制器将收集更多数据,然后才决定是否更改亮度。默认情况下,mResetAmbientLuxAfterWarmUpConfig为true,因此在解除L-Sensor时,mAmbientLuxValid为false。

mAmbientLux表示当前的光照强度值(Lux值)。

2.2.prepareBrightnessAdjustmentSample()
在这个方法中,对旧值做一个记录,然后设置一个10s的Handler去打印log,这个方法也比较简单:

private void prepareBrightnessAdjustmentSample() {
    if (!mBrightnessAdjustmentSamplePending) {//一个标记值
        mBrightnessAdjustmentSamplePending = true;
        //将当前调节值标记为旧的自动调节值
        mBrightnessAdjustmentSampleOldAdjustment = mScreenAutoBrightnessAdjustment;
        //将当前Lux值标记为旧的Lux值,其中如果mAmbientLuxValid为false(解除LSensor后),则标记为-1
        mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
        //计算的自动调节的亮度值
        mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
        //Gamma值
        mBrightnessAdjustmentSampleOldGamma = mLastScreenAutoBrightnessGamma;
    } else {
        mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
    }
    //Handler中仅仅打印Event log
    mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
            BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
}

2.3.setScreenAutoBrightnessAdjustment()
在这个方法中,设置自动调节调节值,并根据调节值是否变化返回结果:

private boolean setScreenAutoBrightnessAdjustment(float adjustment) {
    if (adjustment != mScreenAutoBrightnessAdjustment) {
        //设置新的adjustment值
        mScreenAutoBrightnessAdjustment = adjustment;
        return true;
    }
    return false;
}

其中当亮度条滑到最小时,亮度调节值为-1;当亮度条滑到最大时,亮度调节值为1;当亮度条滑到中间时,亮度调节值为0.

2.4.updateAutoBrightness()
在configure()方法中,如果当adjust值发生变化,或者开启了L-Sensor,则将会调用updateAutoBrightness()方法,这个方法是更新自动亮度的方法,该方法如下:

private void updateAutoBrightness(boolean sendUpdate) {
    //只有当mResetAmbientLuxAfterWarmUpConfig配置为true,且解除L-Sensor时,mAmbientLuxValid为false
    if (!mAmbientLuxValid) {
        return;
    }
    //根据当前的Lux值得到样条曲线中的value
    float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
    float gamma = 1.0f;

    if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
            && mScreenAutoBrightnessAdjustment != 0.0f) {
        //得到adjGamma值
        final float adjGamma = MathUtils.pow(mScreenAutoBrightnessAdjustmentMaxGamma,
                Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
        gamma *= adjGamma;
    }
    if (gamma != 1.0f) {//说明使用了adjGamma
        final float in = value;
        //再次计算value
        value = MathUtils.pow(value, gamma);
    }
    //新的亮度值=value * 255
    int newScreenAutoBrightness =
            clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
    if (mScreenAutoBrightness != newScreenAutoBrightness) {
        //更新亮度值
        mScreenAutoBrightness = newScreenAutoBrightness;
        mLastScreenAutoBrightnessGamma = gamma;
        if (sendUpdate) {//configure()方法中调用时为false
            //回调至DisplayPowerController中
            mCallbacks.updateBrightness();
        }
    }
}

在这个方法中,将计算出最终的亮度值,并根据传入的参数sendUpdate决定是否通过mCallbacks.updateBrightness()进入DisplayPowerController中设置亮度:

//DisplayPowerController.java
@Override
public void updateBrightness() {
    sendUpdatePowerState();
}

从这个方法中也可以看出,mScreenAutoBrightnessAdjustmentMaxGamma和mScreenAutoBrightnessAdjustment对自动调节亮度打开时拖动亮度条调节亮度有很大的影响,前者是一个配置值,后者则在拖动亮度条时设置。
同时,如果想在打开自动调节亮度的情况下使得拖动亮度条无效,则将USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT常亮设置为false即可。

然而需要注意的一点是,当从configure()方法中调用进入updateAutoBrightness()时,传入参数为false,也就是说,不会主动回调至DipplayPowerController的中去更新亮度。那么在自动调节打开的情况下,拖动亮度条,是如何成功设置亮度的呢?如果是此种情况,由于此处已经得到了新的亮度值mScreenAutoBrightness,所以DisplayPowerController中调用了如下方法:

public int getAutomaticScreenBrightness() {
    if (mDozing) {
        return (int) (mScreenAutoBrightness * mDozeScaleFactor);
    }
    return mScreenAutoBrightness;
}

至此,关于自动亮度控制器的初始化和配置相关的流程就分析完毕。接下来来看看LSensor事件的触发以及触发后是如何处理LSensor事件并设置亮度的。

3.LSensor事件触发后的流程
在configure()方法中,对L-Sensor进行了注册,因此当外界亮度改变时,将会回调L-Sensor监听事件:

private final SensorEventListener mLightSensorListener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (mLightSensorEnabled) {
            final long time = SystemClock.uptimeMillis();
            //得到当前光照强度值
            final float lux = event.values[0];
            //处理LSensor事件
            handleLightSensorEvent(time, lux);
        }
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Not used.
    }
};

3.1.handleLightSensorEvent()
当SensorEventListener中收到L-Sensor事件后,获取了当前环境的光强值(lux值),然后在handleLightSensorEvent()中做了下一步的处理:

private void handleLightSensorEvent(long time, float lux) {
    mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);

    //如果环形缓冲区中没有数据,说明此时还未收集光照样例
    if (mAmbientLightRingBuffer.size() == 0) {
        // switch to using the steady-state sample rate after grabbing the initial light sample
        // 重新注册L-Sensor,切换到正常速率,因为第一次注册L-Sensor时使用的是mInitialLightSensorRate
        adjustLightSensorRate(mNormalLightSensorRate);
    }
    //将时间和lux值添加到缓冲区
    applyLightSensorMeasurement(time, lux);
    //更新lux值
    updateAmbientLux(time);
}

在以上方法中,mAmbientLightRingBuffer是一个记录光照强度值和对应时间的环形缓冲区,其大小为:配置的采集光照强度周期 × 额外比例 / LSensor事件速率。在控制器构造方法中,获取了它的实例:

mAmbientLightRingBuffer =
    new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
mInitialHorizonAmbientLightRingBuffer =
    new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);

如果该缓冲区中没有数据,说明还未开始收集,此时调整LSensor事件速率,因为在setLightSensorEnabled()中首次注册LSensor时,使用的速率为mInitialLightSensorRate。此值仅用于获取第一份光照样例,一般情况下,该值等于mNormalLightSensorRate。adjustLightSensorRate()方法如下:

3.2.adjustLightSensorRate()
private void adjustLightSensorRate(int lightSensorRate) {
    // if the light sensor rate changed, update the sensor listener
    if (lightSensorRate != mCurrentLightSensorRate) {
        mCurrentLightSensorRate = lightSensorRate;
        mSensorManager.unregisterListener(mLightSensorListener);
        mSensorManager.registerListener(mLightSensorListener, mLightSensor,
                lightSensorRate * 1000, mHandler);
    }
}

继续进行分析,接下来调用applyLightSensorMeasurement()方法:

3.3.applyLightSensorMeasurement()
    private void applyLightSensorMeasurement(long time, float lux) {
        //LightSensor 可用(打开、可用)之后收集的光照样例的数量
        mRecentLightSamples++;
        //如果当前时间 <= LightSensor开始时间+光照样例采集周期(LSensor开启未超过10s)
        //也就是说,mInitialHorizonAmbientLightRingBuffer中存储了开启LSensor后10s的数据
        if (time <= mLightSensorEnableTime + mAmbientLightHorizon) {
            mInitialHorizonAmbientLightRingBuffer.push(time, lux);
        }
        //删除距离当前mAmbientLightHorizon(10s)秒的数据
        //LSensor500ms上报一次值,因此存储10s内可存储21组数据
        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
        //添加此次数据
        mAmbientLightRingBuffer.push(time, lux);

        // Remember this sample value.
        mLastObservedLux = lux;
        mLastObservedLuxTime = time;
    }

该方法中,对缓冲区中的数据做了处理,移除了指定界限前的数据,同事将新的time和lux值push到了环形缓冲区。
接下来,调用updateAmbientLux(time)方法更新lux值:

3.4.updateAmbientLux()
private void updateAmbientLux(long time) {
    //mAmbientLuxValid为false,说明mResetAmbientLuxAfterWarmUpConfig为ture,也就是说当LSensor 可用后,立即调整亮度
    //因此mResetAmbientLuxAfterWarmUpConfig的功能的实现就在这个if语句中
    if (!mAmbientLuxValid) {
        final long timeWhenSensorWarmedUp =
            mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
        //如果当前时间小于LSensor预热时间,则LSensor not ready yet,此时通过Handler发送定时消息后重新调用
        if (time < timeWhenSensorWarmedUp) {
            mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
                    timeWhenSensorWarmedUp);
            return;
        }
        //开启LSensor后,根据2s内的LSensor数据,立即设置新的Lux值,AMBIENT_LIGHT_SHORT_HORIZON_MILLIS为2000
        setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
        mAmbientLuxValid = true;
        //更新亮度
        updateAutoBrightness(true);
    }
    //置于明亮/昏暗环境下时,多久开始调节亮度
    long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
    long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
    //分别得到距离当前10s内的Lux值和2s内的Lux值
    float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
    float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
    //大于Brightening阀值或小于Darkening阀值,且到达调节时间时
    if (slowAmbientLux >= mBrighteningLuxThreshold &&
            fastAmbientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
            || slowAmbientLux <= mDarkeningLuxThreshold
            && fastAmbientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
        //将fastAmbientLux设置为全局Lux值
        setAmbientLux(fastAmbientLux);
        //开始更新亮度
        updateAutoBrightness(true);
        //重置明亮/昏暗环境下,下次调节亮度时间
        nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
        nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
    }
    //取最小值获得下次调节时间
    long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
    nextTransitionTime =
            nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
    //发送定时消息,到达时间后继续调用updateAmbientLux()
    mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
}

在这个方法中,首先它对mAmbientLuxValid变量进行了判断,如果该值为false,则进入if语句中,计算一个新的lux值,并调用updateAutoBrightness(true)去主动更新亮度。而在前面说过,要使得mAmbientLuxValid为false,则mResetAmbientLuxAfterWarmUpConfig为true,该值在congfig.xml中配置:

<bool name="config_autoBrightnessResetAmbientLuxAfterWarmUp">true</bool>
1
它表示是否当开启LSensor后(打开自动调节亮度且亮屏),LSensor度过预热期后立即调整亮度,所以这个值代表的功能,就在这个if语句中实现的。
当第一次执行updateAmbientLux()后,mAmbientLuxValid将置为true,直到LSensor再次被解除注册。也就是说,这里的if语句只会在LSensor开启后第一次执行,且只执行一次。

这里对涉及到计算lux值的流程暂且略过,只需要知道通过setAmbientLux()将新计算得到的lux值进行了设置,该方法如下:

private void setAmbientLux(float lux) {
    //将lux赋值给表示当前lux的全局变量mAmbientLux
    mAmbientLux = lux;
    //环境亮度阈值,用于使屏幕变亮或变暗的Lux临界值
    mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
    mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
}

继续回到updateAmbientLux()方法中,if(!mAmbientLuxValid)代码块之后,计算了两个时间值nextBrightenTransition和nextDarkenTransition,它们分别表示置于明亮和昏暗环境下时、多久开始调节亮度,该值的计算和防抖动时间有关,相关方法如下:

    private long nextAmbientLightBrighteningTransition(long time) {
        final int N = mAmbientLightRingBuffer.size();
        long earliestValidTime = time;
        //遍历缓冲区,当Lux值小于等于明亮Lux阀值时break,得到第一次小于Lux阀值的一次时间
        for (int i = N - 1; i >= 0; i--) {
            if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
                break;
            }
            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
        }
        //最近一次时间+防抖动时间就是下一次调节亮度时间
        return earliestValidTime + mBrighteningLightDebounceConfig;
    }

    private long nextAmbientLightDarkeningTransition(long time) {
        final int N = mAmbientLightRingBuffer.size();
        long earliestValidTime = time;
        for (int i = N - 1; i >= 0; i--) {
            if (mAmbientLightRingBuffer.getLux(i) >= mDarkeningLuxThreshold) {
                break;
            }
            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
        }
        return earliestValidTime + mDarkeningLightDebounceConfig;
    }

在以上方法中可以看出,是根据第一次小于Lux阀值的时间+防抖时间得到调节亮度的时间,在方法的最后会利用这个时间值,通过Handler发送一个定时消息。

计算完毕下次调节亮度时间后,接下来计算了两个Lux值:slowAmbientLux和fastAmbientLux,这两个值分别是距离此次2s内和10s内的Lux值,根据注释可知,fastAmbientLux一般代表当前的Lux值,slowAmbientLux只是确保长时间内光照是否有所变化。当满足条件后,将开始调用updateAutoBrightness(true)更新自动亮度,并主动回调DisplayPowerController中开始更新背光。

在updateAmbientLux()方法的最后,通过Handler发送一个定时消息,当时间到达后,执行逻辑如下:

private void updateAmbientLux() {
    long time = SystemClock.uptimeMillis();
    //从缓冲区中裁剪掉mAmbientLightHorizon(10)秒前的数据
    mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
    //更新Lux值
    updateAmbientLux(time);
}

关于此处的prune()方法,会在下一篇文章中,分析其算法时进行分析。

以上就是整个自动调节亮度的流程,至于算法,在下一篇文章中进行分析。

猜你喜欢

转载自blog.csdn.net/sdkdlwk/article/details/88368247
今日推荐