android 8.1自動背光隨筆
阿新 • • 發佈:2019-02-11
本文簡單梳理自己對自動背光涉及演算法理解
主要類:
AutomaticBrightnessController.java
DisplayPowerController.java
Spline.java
1.AutomaticBrightnessController中註冊SensorEventListener監聽,LightSensor上報光照值回撥onSensorChanged();
對上報的光照值有以下兩個方法分別來處理:
private void applyLightSensorMeasurement(long time, float lux) { mRecentLightSamples++; // Store all of the light measurements for the intial horizon period. This is to help// diagnose dim wake ups and slow responses in b/27951906. if (time <= mLightSensorEnableTime + mAmbientLightHorizon) { mInitialHorizonAmbientLightRingBuffer.push(time, lux); } mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);//減掉最近十一次之前的光照值 mAmbientLightRingBuffer.push(time, lux);//儲存最近十次光照值 // Remember this sample value.mLastObservedLux = lux; mLastObservedLuxTime = time; if (USE_HUGE_DEBOUNCE) { int index = mScreenAutoBrightnessSpline.getIndex(lux); if ((mAmbientLuxIndex >= ROM_AMBIENT_LIGHT_INDEX) && (index < ROM_AMBIENT_LIGHT_INDEX)) { setLuxThreshold(lux, true); } if (DEBUG) { Slog.d(TAG, "applyLightSensorMeasurement: mAmbientLux=" + mAmbientLux + ", mAmbientLuxIndex=" + mAmbientLuxIndex + ", lux=" + lux + ", index=" + index + ", [" + mDarkeningLuxThreshold + ", " + mBrighteningLuxThreshold + "]"); } } }
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. if (!mAmbientLuxValid) { final long timeWhenSensorWarmedUp = mLightSensorWarmUpTimeConfig + mLightSensorEnableTime; if (time < timeWhenSensorWarmedUp) { if (DEBUG) { Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " + "time=" + time + ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp); } mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, timeWhenSensorWarmedUp); return; } setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS)); mAmbientLuxValid = true; if (DEBUG) { Slog.d(TAG, "updateAmbientLux: Initializing: " + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", mAmbientLux=" + mAmbientLux); } updateAutoBrightness(true); } long nextBrightenTransition = nextAmbientLightBrighteningTransition(time); long nextDarkenTransition = nextAmbientLightDarkeningTransition(time); // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term // change in lighting conditions, and a fast ambient lux to determine what the new // brightness situation is since the slow lux can be quite slow to converge. // // Note that both values need to be checked for sufficient change before updating the // proposed ambient light value since the slow value might be sufficiently far enough away // from the fast value to cause a recalculation while its actually just converging on // the fast value still. float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS); float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS); android.util.Log.i("FM","--mBrighteningLuxThreshold is---"+mBrighteningLuxThreshold+"--nextBrightenTransition---" +nextBrightenTransition+"--mDarkeningLuxThreshold--"+mDarkeningLuxThreshold+"---nextDarkenTransition---"+nextDarkenTransition); if (slowAmbientLux >= mBrighteningLuxThreshold && fastAmbientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time || slowAmbientLux <= mDarkeningLuxThreshold && fastAmbientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) { setAmbientLux(fastAmbientLux); if (DEBUG) { Slog.d(TAG, "updateAmbientLux: " + ((fastAmbientLux > 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. nextTransitionTime = nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate; if (DEBUG) { Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime)); } mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime); }核心演算法在calculateAmbientLux()中進行,即加權平均:
private float calculateAmbientLux(long now, long horizon) { if (DEBUG) { Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")"); } final int N = mAmbientLightRingBuffer.size(); if (N == 0) { Slog.e(TAG, "calculateAmbientLux: No ambient light readings available"); return -1; } // Find the first measurement that is just outside of the horizon. int endIndex = 0; final long horizonStartTime = now - horizon; for (int i = 0; i < N-1; i++) { if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) { endIndex++; } else { break; } } if (DEBUG) { Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" + mAmbientLightRingBuffer.getTime(endIndex) + ", " + mAmbientLightRingBuffer.getLux(endIndex) + ")"); } float sum = 0; float totalWeight = 0; long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS; for (int i = N - 1; i >= endIndex; i--) { long eventTime = 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; } final long startTime = eventTime - now; float weight = calculateWeight(startTime, endTime); float lux = mAmbientLightRingBuffer.getLux(i); 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; }比如:遮蓋感光孔,上報的光照值會逐漸變小(由200逐漸將至0,最後一直為0),mAmbientLightRingBuffer中存進的值就會越來越小,
計算結果小於變暗閾值,且時間上大於變暗過渡時間後,就會使用Spline(儲存了光照值和亮度值對應的map)物件獲取對應的亮度值設定螢幕亮度。