参考 https://blog.csdn.net/FightFightFight/article/details/83626332
自动调节和手动调节的分叉口在DisplayPowerController中的updatePowerState()方法处,这里先对自动调节控制器进行配置,然后若处于自动调节模式,那brightness就从自动调节控制器中获取的
...
boolean autoBrightnessEnabled = false;//是否开启自动亮度调节模式的标记if (mAutomaticBrightnessController != null) {//配置自动调节控制器final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig&& (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND);//doze模式下是否可以使用自动调节autoBrightnessEnabled = mPowerRequest.useAutoBrightness&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)&& brightness < 0;//赋值final boolean userInitiatedChange = autoBrightnessAdjustmentChanged&& mPowerRequest.brightnessSetByUser;//是否拖动了进度条mAutomaticBrightnessController.configure(autoBrightnessEnabled,mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,userInitiatedChange);}
...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;}
关于AutomaticBrightnessController,他负责控制自动调节,获取当前环境下的亮度,处理成亮度值让DisplayPowerController获取
AutomaticBrightnessController
先看被调用的configure()方法,在这里对LightSensor进行注册,如果有改变调整值就改变,然后更新亮度值。在注册了LightSensor以后,就会有对它的监听,来获取实时亮度。后面再说
public void configure(boolean enable, float adjustment, boolean dozing,boolean userInitiatedChange) {// 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.mDozing = dozing;boolean changed = setLightSensorEnabled(enable && !dozing);//注册LightSensor 返回值true表示可用并且成功注册if (enable && !dozing && userInitiatedChange) {prepareBrightnessAdjustmentSample();//记录旧值 包括调整值 亮度值 Lux值 Gamma值}changed |= setScreenAutoBrightnessAdjustment(adjustment);//设置改变后的调整值if (changed) {updateAutoBrightness(false /*sendUpdate*/);//调整值有变化,更改亮度值}}
setLightSensorEnabled() 注册LightSensor
private boolean setLightSensorEnabled(boolean enable) {if (enable) {if (!mLightSensorEnabled) {//可用 进行注册mLightSensorEnabled = true;mLightSensorEnableTime = SystemClock.uptimeMillis();//LightSensor开始的时间mCurrentLightSensorRate = mInitialLightSensorRate;//当前LightSensor事件率mSensorManager.registerListener(mLightSensorListener, mLightSensor,mCurrentLightSensorRate * 1000, mHandler);return true;}} else {if (mLightSensorEnabled) {//不可用 mLightSensorEnabled = false;mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;mRecentLightSamples = 0;mAmbientLightRingBuffer.clear();mInitialHorizonAmbientLightRingBuffer.clear();mCurrentLightSensorRate = -1;mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);mSensorManager.unregisterListener(mLightSensorListener);//解除监听}}return false;}
上面注册或者解除注册LightSensor的方法,在这里通过mLightSensorEnabled判断当前LightSensor的状态是否可用,如果不可用,要清除缓存的亮度值然后解除注册;prepareBrightnessAdjustmentSample()主要是对上一次的亮度值、调整值、Gamma值、Lux值进行一个记录,然后setScreenAutoBrightnessAdjustment(adjustment)方法是设置最新的更改过的调整值,这里这个调整值范围在-1~1,滑动条在最小是-1,在最大是1,中间是0
在configure()方法里如果注册LightSensor或者调整值发生变化,都会进行亮度值的更新updateAutoBrightness(false /sendUpdate/),这里参数是false,不主动把改变后的亮度值返回而是给他提供一个方法getAutomaticScreenBrightness()来获取亮度
public int getAutomaticScreenBrightness() {if (mDozing) {return (int) (mScreenAutoBrightness * mDozeScaleFactor);}return mScreenAutoBrightness;}
其余情况,监听到亮度变化的时候 是主动请求改变亮度的
updateAutoBrightness()
private void updateAutoBrightness(boolean sendUpdate) {//这个参数当解除LightSensor的时候或者配置的mResetAmbientLuxAfterWarmUpConfig配置为true是为false//mResetAmbientLuxAfterWarmUpConfig配置为true表示,根据当前传感器的数据调整亮度if (!mAmbientLuxValid) {return;}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;//使用这个Gamma值if (DEBUG) {Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);}}if (gamma != 1.0f) {//使用了调整后的Gamma值final float in = value;value = MathUtils.pow(value, gamma);//重新获取个valueif (DEBUG) {Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma+ ", in=" + in + ", out=" + value);}}int newScreenAutoBrightness =clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));//获取新的亮度值if (mScreenAutoBrightness != newScreenAutoBrightness) {//亮度有改变if (DEBUG) {Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="+ mScreenAutoBrightness + ", newScreenAutoBrightness="+ newScreenAutoBrightness);}mScreenAutoBrightness = newScreenAutoBrightness;//更新亮度值mLastScreenAutoBrightnessGamma = gamma;//更新Gamma值if (sendUpdate) {//回调通知DisplayPowerController改变了亮度mCallbacks.updateBrightness();}}}
上面是在自动调节的情况下,用户进行拖拽进度条,对亮度的改变,如果禁止在自动调节模式下拖拽进度条改变亮度,可以将上面的USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT设置为flase;
下面是在注册了LightSensor以后,亮度改变以后,回调的监听函数做了什么
mLightSensorListener 监听
private final SensorEventListener mLightSensorListener = new SensorEventListener() {@Overridepublic void onSensorChanged(SensorEvent event) {if (mLightSensorEnabled) {final long time = SystemClock.uptimeMillis();//获取了当前时间final float lux = event.values[0];//获取光照强度值handleLightSensorEvent(time, lux);//处理数据}}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// Not used.}};
获取了时间和光照强度以后,调用 handleLightSensorEvent(time, 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//重新注册LightSensor,把速率换成正常速率adjustLightSensorRate(mNormalLightSensorRate);}applyLightSensorMeasurement(time, lux);//把时间和Lux值添加到缓冲区updateAmbientLux(time);//更新lux 为啥参数是time???}
mAmbientLightRingBuffer是一个存储收集来的数据的缓冲区,没有数据表明没开始收集,这时要重新注册LightSensor,并且把速率改为正常速率,一般都是这个正常速率,只有在配置的时候,传进来的是初始速率,初始速率表示获取第一份数据。
然后要把数据添加到缓冲区
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;}
上面先是把记录的样例数量加1,然后判断当前时间是否在开启LightSensor后的一个采集周期内,mAmbientLightHorizon是一个周期,是10s;然后mAmbientLightRingBuffer存储当前时间往前10s内的光照数据,每0.5s上报一次,这里一共有21组数据;然后去更新光照强度
updateAmbientLux(time)
方法的参数是time,也就是当前时间,因为存储光照样例是按照时间和对应时间的光照强度存储的,可以用这个时间来获取对应的光强
private void updateAmbientLux(long time) {// If the light sensor was just turned on then immediately update our initial// estimate of the current ambient light level.//这个方法只在LightSensor注册的时候执行一次,还是当mResetAmbientLuxAfterWarmUpConfig的值被配置为true的时候,表示立刻更新亮度if (!mAmbientLuxValid) {//预热时间 = 配置的预热时间+开启LightSensor开启的时间final long timeWhenSensorWarmedUp =mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;//如果时间小于预热时间,发送一个handleMessageif (time < timeWhenSensorWarmedUp) {if (DEBUG) {Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: "+ "time=" + time+ ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);}mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,timeWhenSensorWarmedUp);return;}//设置lux值,里面参数是通过当前时间拿到的lux值setAmbientLux(calculateAmbientLux(time));mAmbientLuxValid = true;if (DEBUG) {Slog.d(TAG, "updateAmbientLux: Initializing: "+ "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer+ ", mAmbientLux=" + mAmbientLux);}//更新自动亮度updateAutoBrightness(true);}//明亮环境下,下一次更新的时间long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);//昏暗环境下 下一次更新的时间long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);//获取计算过后的luxfloat ambientLux = calculateAmbientLux(time);//如果计算过后的值超出最亮或者最暗,并且到达调节的时间if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time|| ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {setAmbientLux(ambientLux);//设置全局lux变量if (DEBUG) {Slog.d(TAG, "updateAmbientLux: "+ ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "+ "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold+ ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer+ ", mAmbientLux=" + mAmbientLux);}updateAutoBrightness(true);//更新亮度值nextBrightenTransition = nextAmbientLightBrighteningTransition(time);//重置下一次更新的时间nextDarkenTransition = nextAmbientLightDarkeningTransition(time);//重置下一次更新的时间}//取最小值 作为下一次更新的时间long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);// If one of the transitions is ready to occur, but the total weighted ambient lux doesn't// exceed the necessary threshold, then it's possible we'll get a transition time prior to// now. Rather than continually checking to see whether the weighted lux exceeds the// threshold, schedule an update for when we'd normally expect another light sample, which// should be enough time to decide whether we should actually transition to the new// weighted ambient lux or not.//判断更新时间是否在当前时间之后,若不在,就将更新时间设置为当前时间+一个LightSensor的速率时间nextTransitionTime =nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;if (DEBUG) {Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "+ nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));}//延时的handleMessage 到时间以后 会执行updateAmbientLux()mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);}private void updateAmbientLux() {long time = SystemClock.uptimeMillis();//获取当前时间 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);//清除记录中当前时间10s以前的数据updateAmbientLux(time);//更新lux值}
这里面对lux的计算方法是calculateAmbientLux(time)
calculateAmbientLux(time)
//使用加权平均计算方法,算出来luxprivate float calculateAmbientLux(long now) {final int N = mAmbientLightRingBuffer.size();//容量if (N == 0) {Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");return -1;}float sum = 0;//计算lux*权重的总和float totalWeight = 0;//权重总和long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;for (int i = N - 1; i >= 0; i--) {//存储的时间-当前时间 <0long startTime = (mAmbientLightRingBuffer.getTime(i) - now);float weight = calculateWeight(startTime, endTime);//计算权重float lux = mAmbientLightRingBuffer.getLux(i);//获取lux值if (DEBUG) {Slog.d(TAG, "calculateAmbientLux: [" +(startTime) + ", " +(endTime) + "]: lux=" + lux + ", weight=" + weight);}totalWeight += weight;sum += mAmbientLightRingBuffer.getLux(i) * weight;endTime = startTime;}if (DEBUG) {Slog.d(TAG, "calculateAmbientLux: totalWeight=" + totalWeight +", newAmbientLux=" + (sum / totalWeight));}return sum / totalWeight;}
拿到重新计算之后的lux值以后 就执行setAmbientLux(float lux)方法,
private void setAmbientLux(float lux) {mAmbientLux = lux;mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);//更新阈值mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);//更新阈值}
这个方法里的mDynamicHysteresis是一个HysteresisLevel类,用来帮助计算Lux的阈值,判断亮度变化的时候,变到哪个值开始改变屏幕亮度。