frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.javapublicDisplayPowerController(......){......// 使能开关mUseSoftwareAutoBrightnessConfig=resources.getBoolean(com.android.internal.R.bool.config_automatic_brightness_available);......if(mUseSoftwareAutoBrightnessConfig){// 光感数组int[]lux=resources.getIntArray(com.android.internal.R.array.config_autoBrightnessLevels);// 背光亮度数组int[]screenBrightness=resources.getIntArray(com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);// 其它一些配置intlightSensorWarmUpTimeConfig=resources.getInteger(com.android.internal.R.integer.config_lightSensorWarmupTime);finalfloatdozeScaleFactor=resources.getFraction(com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,1,1);// 创建自动背光样条SplinescreenAutoBrightnessSpline=createAutoBrightnessSpline(lux,screenBrightness);if(screenAutoBrightnessSpline==null){// 如果lux, brightness不合要求,禁用自动背光Slog.e(TAG,"Error in config.xml. config_autoBrightnessLcdBacklightValues "+"(size "+screenBrightness.length+") "+"must be monotic and have exactly one more entry than "+"config_autoBrightnessLevels (size "+lux.length+") "+"which must be strictly increasing. "+"Auto-brightness will be disabled.");mUseSoftwareAutoBrightnessConfig=false;}else{......mAutomaticBrightnessController=newAutomaticBrightnessController(this,handler.getLooper(),sensorManager,screenAutoBrightnessSpline,...// gamma, 最大最小值等其他配置}}
frameworks/base/core/java/android/util/Spline.javapublicstaticSplinecreateSpline(float[]x,float[]y){// 是否严格单调递增if(!isStrictlyIncreasing(x)){thrownewIllegalArgumentException("The control points must all have strictly "+"increasing X values.");}// 单调的还是线性的if(isMonotonic(y)){// 创建单调三次样条插值returncreateMonotoneCubicSpline(x,y);}else{returncreateLinearSpline(x,y);}}
publicstaticSplinecreateMonotoneCubicSpline(float[]x,float[]y){returnnewMonotoneCubicSpline(x,y);}publicstaticclassMonotoneCubicSplineextendsSpline{// 主要的就是这三个数组,横坐标x,纵坐标y,以及相邻点的斜率privatefloat[]mX;privatefloat[]mY;privatefloat[]mM;publicMonotoneCubicSpline(float[]x,float[]y){....// d存放相邻点的斜率,m存放相邻两斜率的平均值float[]d=newfloat[n-1];// could optimize this outfloat[]m=newfloat[n];// Compute slopes of secant lines between successive points.for(inti=0;i<n-1;i++){floath=x[i+1]-x[i];...// 相邻点斜率d[i]=(y[i+1]-y[i])/h;}// Initialize the tangents as the average of the secants.m[0]=d[0];for(inti=1;i<n-1;i++){// 相邻两斜率的平均值m[i]=(d[i-1]+d[i])*0.5f;}m[n-1]=d[n-2];// Update the tangents to preserve monotonicity.// 再次更新m以保持单调性for(inti=0;i<n-1;i++){if(d[i]==0f){// successive Y values are equalm[i]=0f;m[i+1]=0f;}else{floata=m[i]/d[i];floatb=m[i+1]/d[i];if(a<0f||b<0f){thrownewIllegalArgumentException("The control points must have "+"monotonic Y values.");}floath=(float)Math.hypot(a,b);if(h>3f){floatt=3f/h;m[i]*=t;m[i+1]*=t;}}}mX=x;mY=y;mM=m;}
privatevoidupdateAmbientLux(longtime){// If the light sensor was just turned on then immediately update our initial// estimate of the current ambient light level.if(!mAmbientLuxValid){......// 打开sensor后第一次更新数据情况,略过...}// 计算明暗变化的时间点longnextBrightenTransition=nextAmbientLightBrighteningTransition(time);longnextDarkenTransition=nextAmbientLightDarkeningTransition(time);// 计算10s和2s内的luxfloatslowAmbientLux=calculateAmbientLux(time,AMBIENT_LIGHT_LONG_HORIZON_MILLIS);floatfastAmbientLux=calculateAmbientLux(time,AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);// 如果满足去抖的要求,会进行lux和亮度的计算更新if(slowAmbientLux>=mBrighteningLuxThreshold&&fastAmbientLux>=mBrighteningLuxThreshold&&nextBrightenTransition<=time||slowAmbientLux<=mDarkeningLuxThreshold&&fastAmbientLux<=mDarkeningLuxThreshold&&nextDarkenTransition<=time){// 更新lux和明暗lux阀值setAmbientLux(fastAmbientLux);// 这个log应该放在setAmbientLux()前面,不然 fastAmbientLux > mAmbientLux永远为falseif(DEBUG){Slog.d(TAG,"updateAmbientLux: "+((fastAmbientLux>mAmbientLux)?"Brightened":"Darkened")+": "+"mBrighteningLuxThreshold="+mBrighteningLuxThreshold+", mAmbientLightRingBuffer="+mAmbientLightRingBuffer+", mAmbientLux="+mAmbientLux);}// 更新亮度updateAutoBrightness(true);......mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,nextTransitionTime);}
privatefloatcalculateAmbientLux(longnow,longhorizon){......// Find the first measurement that is just outside of the horizon.intendIndex=0;// 计算出指定时间的开始下标finallonghorizonStartTime=now-horizon;for(inti=0;i<N-1;i++){if(mAmbientLightRingBuffer.getTime(i+1)<=horizonStartTime){endIndex++;}else{break;}}......floatsum=0;floattotalWeight=0;longendTime=AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;for(inti=N-1;i>=endIndex;i--){longeventTime=mAmbientLightRingBuffer.getTime(i);if(i==endIndex&&eventTime<horizonStartTime){// If we're at the final value, make sure we only consider the part of the sample// within our desired horizon.eventTime=horizonStartTime;}finallongstartTime=eventTime-now;// 权值计算floatweight=calculateWeight(startTime,endTime);floatlux=mAmbientLightRingBuffer.getLux(i);......totalWeight+=weight;sum+=mAmbientLightRingBuffer.getLux(i)*weight;endTime=startTime;}......// 加权平均returnsum/totalWeight;}
frameworks/base/core/java/android/util/Spline.javapublicstaticclassMonotoneCubicSplineextendsSpline{......@Overridepublicfloatinterpolate(floatx){......// 小于最小lux,直接反回brightness[0]if(x<=mX[0]){returnmY[0];}// 大于最大的lux, 直接返回最大的if(x>=mX[n-1]){returnmY[n-1];}// Find the index 'i' of the last point with smaller X.// We know this will be within the spline due to the boundary tests.inti=0;// 刚好落在采样点上while(x>=mX[i+1]){i+=1;if(x==mX[i]){returnmY[i];}}// Perform cubic Hermite spline interpolation.floath=mX[i+1]-mX[i];floatt=(x-mX[i])/h;// 三次插值计算return(mY[i]*(1+2*t)+h*mM[i]*t)*(1-t)*(1-t)+(mY[i+1]*(3-2*t)+h*mM[i+1]*(t-1))*t*t;}
插值时,大于最大小于最小或者落在点上的情况都好说,直接返回就行了 注意 mX[0] 并不是 config_autoBrightnessLevels 中的第一个lux, 实际上 createAutoBrightnessSpline() 时 float[] x = new float[n]; 其实mX[0] = 0;
<!-- Fast brightness animation ramp rate in brightness units per second--><integertranslatable="false"name="config_brightness_ramp_rate_fast">180</integer><!-- Slow brightness animation ramp rate in brightness units per second--><integertranslatable="false"name="config_brightness_ramp_rate_slow">60</integer>