1. 程式人生 > >android 8.1自動背光隨筆

android 8.1自動背光隨筆

本文簡單梳理自己對自動背光涉及演算法理解

主要類:

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)物件獲取對應的亮度值設定螢幕亮度。