亮度调节之自动调节

news/2024/11/17 6:27:58/

参考 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的阈值,判断亮度变化的时候,变到哪个值开始改变屏幕亮度。


http://www.ppmy.cn/news/451209.html

相关文章

2306d的闭包问题

原文 首先,D的闭包是个好主意.我使用了C的成员函数指针;它们在语法上很糟糕,但概念很好,而闭包更好. D的闭包有些问题,有些是明显错误,有些是不应该不在语言中的改进. 不能调用某些闭包 这很奇怪,但这是真的. 一个问题是常和不变目前没有扩展到闭包环境.要求常和不变的传递性…

Qt 每月收支计算

Qt 每月收支计算&#xff0c;针对每月有支出&#xff08;房贷、车贷、花呗、借呗&#xff09;的情况&#xff0c;计算收支明细&#xff0c;直观看到未来的个人经济情况&#xff0c;培养良好的消费习惯&#xff0c;进行理性的财富支配&#xff0c;量入为出。 #include "mai…

哈希表--day3--(leetcode349/leetcode350)

leetcode349. 两个数组的交集 链接 基本思路 注意题目特意说明&#xff1a;输出结果中的每个元素一定是唯一的&#xff0c;也就是说输出的结果的去重的&#xff0c; 同时可以不考虑输出结果的顺序 这道题用暴力的解法时间复杂度是O(n^2)&#xff0c;那来看看使用哈希法进一…

mateRS能升级鸿蒙系统吗,为什么万元机华为maters保时捷玩吃鸡真么垃圾

满意答案 plae761576 2019.04.06 采纳率&#xff1a;45% 等级&#xff1a;8 已帮助&#xff1a;1160人 现在突然发现好多自媒体都在无下限的刷三观&#xff0c;为了点阅读量&#xff0c;想尽办法给网友们出玩《绝地求生》最低配置&#xff0c;最近看到一个大V自媒体竟然说显…

华为mate20 android,华为MateRS对比华为mate20RS,终于让安卓手机坐上了头等舱!

原标题&#xff1a;华为MateRS对比华为mate20RS&#xff0c;终于让安卓手机坐上了头等舱&#xff01; 最近华为mate20RS正式开卖了&#xff0c;但是却没有现货&#xff0c;因此也出现了很多黄牛在加价售卖这款限量版的手机。今天我们来跟大家说说上一代的限量版华为MateRS跟最新…

华为mate40计算机,华为Mate40兼容欧米多手机电脑,秒变笔电轻办公

万众瞩目的华为Mate40将于10月22日首发&#xff0c;作为史上最强大的华为旗舰手机&#xff0c;Mate40不仅以超强性能吊足了大家的胃口&#xff0c;也因为或将绝版的麒麟9000芯片&#xff0c;充满了悲情色彩&#xff0c;引得众人格外关注这款新机的一举一动。 根据爆料&#xff…

华为mate40pro+和华为mate40RS保时捷有什么区别

华为mate40pro标志性星环设计&#xff0c;来自宇宙的设计灵感&#xff0c;令科技与艺术环环相扣。浪漫秘银&#xff0c;经典黑白&#xff0c;还有黄色和绿色在素皮上带来的温润触感。来&#xff0c;感受一下从视觉到指尖的美妙。 华为Mate40预约抢购地址&#xff1a;https://ww…

【Java高级语法】(六)内部类Inner Class:这可能是史上最全的关于内部类的学习资料~

Java高级语法详解之包装类 :one: 概念:two: 优缺点:three: 使用2.1 成员内部类2.2 局部内部类2.3 匿名内部类2.4 静态内部类2.5 小结&#xff1a;外部类访问四种内部类的特点2.6 小结&#xff1a;其他类访问四种内部类的特点 :four: 内部类与外部类的关系:five: 应用场景:six: …