AAL与CABC背光选择(两种方式控制背光):
参考[FAQ05966]
89平台支持BB端CABC(即AAL)或LCM端CABC方式控制背光,两种方式使用方法如下
【BB端CABC(即AAL)】
- 打开功能,向MTK申请patch,并在ProjectConfig.mk中打开MTK_AAL_SUPPORT = yes
【LCM端CABC】
- 对于Video Mode,ALPS.JB2.MP.V1.3(包括1.3)之前的版本,请向MTK申请patch
- lcm driver中实现set_backlight接口
- cust_leds.c(包括lk与kernel中的两支文件)设置如下
config_automatic_brightness_available 自动亮度调节控制开关
BRIGHTENING_LIGHT_HYSTERESIS ---变得更亮,只有达到比上个lux值高出这个百分比才认为是valid
DARKENING_LIGHT_HYSTERESIS ---变得更暗,只有比上个lux值低出这个百分比才认为是valid
<bool name="config_autoBrightnessResetAmbientLuxAfterWarmUp">truebool>亮屏时是否重舍弃上次灭屏时的采集值。true 表示舍弃,这个时候采集 config_lightSensorWarmupTime 这个时间后 马上计算出当前环境值,波动性较大
false 表示重新根据 BRIGHTENING_LIGHT_HYSTERESIS、DARKENING_LIGHT_HYSTERESIS计算满足阈值条件值,这样较平滑,需要花些时间才能调节到当前环境值。
<integer name="config_lightSensorWarmupTime">0integer>
<integer name="config_autoBrightnessAmbientLightHorizon">10000integer>采样周期
<integer name="config_autoBrightnessLightSensorRate">250integer>light-sensor 采样率
变亮持续时间
变暗持续时间
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
// Mediatek AAL support
private long mPrevLogTime = 0L;
private float mPrevLogLux = 0.0f;
@Override
public void onSensorChanged(SensorEvent event) {
if (DEBUG) Slog.d(TAG, "onSensorChanged: mLightSensorEnabled=" + mLightSensorEnabled +
", mAmbientLuxValid=" + mAmbientLuxValid);
if (mLightSensorEnabled) {
final long time = SystemClock.uptimeMillis();
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
// Mediatek AAL support : long period and significant lux changed
if (time - mPrevLogTime >= 500L ||
mPrevLogLux * 1.2f <= lux || lux * 1.2f <= mPrevLogLux) {
if (DEBUG) Slog.d(TAG, "onSensorChanged: lux = " + lux);
mPrevLogTime = time;
mPrevLogLux = lux;
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
private boolean setLightSensorEnabled(boolean enable) {
if (enable != mLightSensorEnabled) {
Slog.d(TAG, "setLightSensorEnabled: enable=" + enable +
", mLightSensorEnabled=" + mLightSensorEnabled +
", mAmbientLuxValid=" + mAmbientLuxValid +
", mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
}
if (enable) {
if (!mLightSensorEnabled) {
mLightSensorEnabled = true;
mLightSensorEnableTime = SystemClock.uptimeMillis();
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
mLightSensorRate * 1000, mHandler);
return true;
}
} else {
if (mLightSensorEnabled) {
mLightSensorEnabled = false;
mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
mRecentLightSamples = 0;
mAmbientLightRingBuffer.clear();
mInitialHorizonAmbientLightRingBuffer.clear();
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
mSensorManager.unregisterListener(mLightSensorListener);
}
}
return false;
}
//light sensor 监听到背光事件处理
final long time = SystemClock.uptimeMillis(); final float lux = event.values[0]; handleLightSensorEvent(time, lux);
private void handleLightSensorEvent(long time, float lux) {
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
applyLightSensorMeasurement(time, lux);
updateAmbientLux(time);
}
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;
}
mInitialHorizonAmbientLightRingBuffer.push(time, lux);
从自动背光enable开始10s采集到的环境光线值复制给mInitialHorizonAmbientLightRingBuffer
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon); 就是去掉当前比采样周期mAmbientLightHorizon早的数据,并确定插入有效数组位置
mAmbientLightRingBuffer.push 将值插入有效数组位置
其中mAmbientLightRingBuffer对象可以简单认为是一个循环数组,大小为通常
mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate); 即采样周期内采样次数的一个比例(1.5)放大
//处理采样的数组值并获得lux
private void updateAmbientLux(long time) {
if (DEBUG) Slog.d(TAG, "updateAmbientLux: mAmbientLuxValid=" + mAmbientLuxValid +
", AAL=" + DisplayPowerController.MTK_AAL_SUPPORT);
// If the light sensor was just turned on then immediately update our initial
// estimate of the current ambient light level.
if (!mAmbientLuxValid) { //config_autoBrightnessResetAmbientLuxAfterWarmUp 为false
final long timeWhenSensorWarmedUp =
mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
if (time < timeWhenSensorWarmedUp) {//config_lightSensorWarmupTime warmUP time,即重置等待采样时间
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));//config_lightSensorWarmupTime 采样时间到计算获取lux值
mAmbientLuxValid = true;
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Initializing: "
+ "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
+ ", mAmbientLux=" + mAmbientLux);
}
updateAutoBrightness(true);//更新背光亮度
}
long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
float ambientLux = calculateAmbientLux(time);
if (DisplayPowerController.MTK_AAL_SUPPORT) {
Slog.d(TAG, "updateAmbientLux: ambientLux=" + ambientLux
+ ", timeToBrighten=" + (nextBrightenTransition - time)
+ ", timeToDarken=" + (nextDarkenTransition - time)
+ ", current=" + mAmbientLux);
}
if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
|| ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
setAmbientLux(ambientLux);
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.
nextTransitionTime =
nextTransitionTime > time ? nextTransitionTime : time + mLightSensorRate;
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
+ nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
}
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
}
long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
从mAmbientLightRingBuffer中从晚到早找到达到变得更亮的阈值的亮度时间点,这里是说计算出的下一次达到稳定的时间,如果这个时间比当前时间早,说明已经超出了变亮或者变暗的时间。即已经达到了config_autoBrightnessBrighteningLightDebounce 、config_autoBrightnessDarkeningLightDebounce要求的时间
从mAmbientLightRingBuffer中从晚到早找到达到变得更暗的阈值的亮度时间点
float ambientLux = calculateAmbientLux(time);
根据当前时间获取一个lux值
if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
|| ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
setAmbientLux(ambientLux);
updateAutoBrightness(true);
nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
}
如果获取的lux值达到变亮(暗)阈值且时间达到稳定的时间,小于当前时间就是说明达到了config_autoBrightnessBrighteningLightDebounce 、config_autoBrightnessDarkeningLightDebounce要求的时间。这个时候就认为计算出的lux值是有效的,就设置lux值,并setAmbientLux重新计算得出阈值。紧接着更新背光亮度,这个时候由于重新获取了阈值,并重新算出下一次。
private void setAmbientLux(float lux) { mAmbientLux = lux; mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS); mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS); DisplayPowerController.nativeSetDebouncedAmbientLight((int) lux); }
mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
下一次更新的时间消息。
private 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;
float totalWeight = 0;
long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
for (int i = N - 1; i >= 0; i--) {
long startTime = (mAmbientLightRingBuffer.getTime(i) - now);
// Mediatek AAL support
if (DisplayPowerController.MTK_AAL_SUPPORT) {
if (startTime < -MTK_AAL_AMBIENT_LIGHT_HORIZON && totalWeight > 0)
break;
}
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;
}
long startTime = (mAmbientLightRingBuffer.getTime(i) - now);就是获取与当前时间的时间负差
float weight = calculateWeight(startTime, endTime); float lux = mAmbientLightRingBuffer.getLux(i);
根据两个时间点计算出一个比重,再获取lux值
totalWeight += weight;
sum += mAmbientLightRingBuffer.getLux(i) * weight;
endTime = startTime;
根据比重计算出lux,并从新设置时间点
AAL框架
http://www.cnblogs.com/lexuele/p/5131396.html
/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
越大越快
调节开关控制
MTK_AAL_SUPPORT
MTK_ULTRA_DIMMING_SUPPORT
adb shell dumpsys AAL --function 1 关闭AAL ,及关闭背光上报模块
config_screenBrightnessSettingMinimum 屏膜最小亮度
config_autoBrightnessLcdBacklightValues
frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
控制display 的power 状态
处理距离、灯传感器、及动画
与PMS 其它部分独立,仅仅通过异步回调通知PMS状态改变
事件都是在它的handler中处理
PMS保证在显示准备好之前它一直持有suspend blocker
final class DisplayPowerController implements AutomaticBrightnessController.Callbacks实现了接口
public void updateBrightness() {
sendUpdatePowerState();
}
this这个接口作为mAutomaticBrightnessController = new AutomaticBrightnessController(this ....的回调
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
管理和通知系统显示 依赖于DisplayAdapter
private final class LocalService extends DisplayManagerInternal {
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
DisplayBlanker blanker = new DisplayBlanker() {
@Override
public void requestDisplayState(int state, int brightness) {
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state, brightness);
}
callbacks.onDisplayStateChange(state);
if (state != Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state, brightness);
}
}
};
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
}
}
DMS 通过 DisplayPowerController 实现显示状态控制,DisplayPowerCallbacks 用于回调回PMS
/** * Interface used to update the actual display state. */ public interface DisplayBlanker { void requestDisplayState(int state, int brightness); }
frameworks\base\services\core\java\com\android\server\display\AutomaticBrightnessController.java
光传感器
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
// Mediatek AAL support
private long mPrevLogTime = 0L;
private float mPrevLogLux = 0.0f;
@Override
public void onSensorChanged(SensorEvent event) {
if (DEBUG) Slog.d(TAG, "onSensorChanged: mLightSensorEnabled=" + mLightSensorEnabled +
", mAmbientLuxValid=" + mAmbientLuxValid);
if (mLightSensorEnabled) {
final long time = SystemClock.uptimeMillis();
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
// Mediatek AAL support : long period and significant lux changed
if (time - mPrevLogTime >= 500L ||
mPrevLogLux * 1.2f <= lux || lux * 1.2f <= mPrevLogLux) {
if (DEBUG) Slog.d(TAG, "onSensorChanged: lux = " + lux);
mPrevLogTime = time;
mPrevLogLux = lux;
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
frameworks\base\services\core\java\com\android\server\display\AutomaticBrightnessController.java
光传感器
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
// Mediatek AAL support
private long mPrevLogTime = 0L;
private float mPrevLogLux = 0.0f;
@Override
public void onSensorChanged(SensorEvent event) {
if (DEBUG) Slog.d(TAG, "onSensorChanged: mLightSensorEnabled=" + mLightSensorEnabled +
", mAmbientLuxValid=" + mAmbientLuxValid);
if (mLightSensorEnabled) {
final long time = SystemClock.uptimeMillis();
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
// Mediatek AAL support : long period and significant lux changed
if (time - mPrevLogTime >= 500L ||
mPrevLogLux * 1.2f <= lux || lux * 1.2f <= mPrevLogLux) {
if (DEBUG) Slog.d(TAG, "onSensorChanged: lux = " + lux);
mPrevLogTime = time;
mPrevLogLux = lux;
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
AAL与CABC背光选择(两种方式控制背光):
参考[FAQ05966]
89平台支持BB端CABC(即AAL)或LCM端CABC方式控制背光,两种方式使用方法如下
【BB端CABC(即AAL)】
- 打开功能,向MTK申请patch,并在ProjectConfig.mk中打开MTK_AAL_SUPPORT = yes
【LCM端CABC】
- 对于Video Mode,ALPS.JB2.MP.V1.3(包括1.3)之前的版本,请向MTK申请patch
- lcm driver中实现set_backlight接口
- cust_leds.c(包括lk与kernel中的两支文件)设置如下
private void setAmbientLux(float lux) { mAmbientLux = lux; mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS); mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS); DisplayPowerController.nativeSetDebouncedAmbientLight((int) lux); }
BRIGHTENING_LIGHT_HYSTERESIS ---变得更亮,只有达到
DARKENING_LIGHT_HYSTERESIS ---变得更暗
private void setAmbientLux(float lux) { mAmbientLux = lux; mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS); mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS); DisplayPowerController.nativeSetDebouncedAmbientLight((int) lux); }