1、手动设置背光API
// 修改当前Activity界面的窗口亮度
private void setScreenLight(int brightness) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.screenBrightness = Float.valueOf(brightness) * (1f / 255f);
getWindow().setAttributes(lp);
}
// 修改系统的亮度值
public void setScreenLight(int brightness) {
Uri uri = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
ContentResolver contentResolver = getContentResolver();
Settings.System.putInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, brightness);
contentResolver.notifyChange(uri, null);
}
2、设置系统背光默认亮度值
#frameworks/base/core/res/res/values/config.xml
2
2
系统背光节点路径:/sys/class/leds/lcd-backlight/brightness
3、自动背光配置设置
自动背光涉及光感值与亮度值对应,需要根据项目进行设置光感和背光值数组,一一对应。
# frameworks/base/core/res/res/values/config.xml
... 填写亮度值数组 ...
... 填写光感值数组 ...
系统手动设置,待机休眠等都是通过 PowerManagerService.java 统一管理,自动背光则是由 AutomaticBrightnessController.java 管理。最后统一调用 DisplayPowerController.java 进行处理。
1、frameworks/base/services/core/java/com/android/server/display/AutomaticBrightnessController.java 主要相关操作:
通过监听L-sersor 值变化发送 handleLightSensorEvent 走到 updateAutoBrightness 函数,最终调用到 DisplayPowerController.java updateBrightness函数。
// 内部创建一个光感监听
private final SensorEventListener mLightSensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (mLightSensorEnabled) {
final long time = SystemClock.uptimeMillis();
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not used.
}
};
// 通知update背光
private void updateAutoBrightness(boolean sendUpdate) {
if (!mAmbientLuxValid) {
return;
}
// 根据光感值计算对应背光值
float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
float gamma = 1.0f;
if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
&& mScreenAutoBrightnessAdjustment != 0.0f) {
final float adjGamma = MathUtils.pow(mScreenAutoBrightnessAdjustmentMaxGamma,
Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
gamma *= adjGamma;
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
}
}
if (gamma != 1.0f) {
final float in = value;
value = MathUtils.pow(value, gamma);
if (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;
if (sendUpdate) {
// 通知mCallbacks背光改变,mCallbacks 即是 DisplayPowerController 类对象
mCallbacks.updateBrightness();
}
}
}
// mCallbacks中调用获取当前的自动背光值,后续进行设置
public int getAutomaticScreenBrightness() {
if (!mAmbientLuxValid) {
return -1;
}
if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
return (int) (mScreenAutoBrightness * mDozeScaleFactor);
}
return mScreenAutoBrightness;
}
2、frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java 主要操作:
上层背光相关操作最终都是走到 PowerManagerService ,统一处理,这里只看设置 SCREEN_BRIGHTNESS 值的流程。通过 SettingsObserver 监听值变化,最终调用到 DisplayPowerController.java requestPowerState 函数。
// 系统启动时进行初始化操作
public void systemReady(IAppOpsService appOps) {
... ...
// 绑定监听
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS),
false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
... ...
}
// 监听变化发送 handleSettingsChangedLocked
private final class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
synchronized (mLock) {
handleSettingsChangedLocked();
}
}
}
//handleSettingsChangedLocked -> updatePowerStateLocked -> updateDisplayPowerStateLocked
/**
*异步更新显示电源状态。 更新完成后,mDisplayReady将设置为true。 显示控制器会发布一条消息,告诉
*我们实际的显示电源状态何时已更新,因此我们回到这里进行仔细检查并完成。
*每次该功能都会重新计算显示功率状态。
*@return如果显示准备就绪,则为True。
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
DIRTY_QUIESCENT)) != 0) {
mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
... ...
// 修改更新 mDisplayPowerRequest 亮度值等属性
mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
mDisplayPowerRequest.useAutoBrightness = autoBrightness;
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
... ...
// 最终调用 DisplayPowerController 处理
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,mRequestWaitForNegativeProximity);
... ...
}
return mDisplayReady && !oldDisplayReady;
}
3、frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java 主要相关方法分析
通过 Settings.System.SCREEN_BRIGHTNESS 手动设置值,是从调用 requestPowerState 开始,最终调用 sendUpdatePowerStateLocked,如下
// 通过设置settings值手动更新亮度调用
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
if (DEBUG) {
Slog.d(TAG, "requestPowerState: "
+ request + ", waitForNegativeProximity=" + waitForNegativeProximity);
}
synchronized (mLock) {
boolean changed = false;
mRequestPowerStateChangedByUser = false;
if (waitForNegativeProximity
&& !mPendingWaitForNegativeProximityLocked) {
mPendingWaitForNegativeProximityLocked = true;
changed = true;
}
if (mPendingRequestLocked == null) {
mPendingRequestLocked = new DisplayPowerRequest(request);
changed = true;
} else if (!mPendingRequestLocked.equals(request)) {
// 这里不同是手动设置的调用
mPendingRequestLocked.copyFrom(request);
changed = true;
mRequestPowerStateChangedByUser = true;
}
if (changed) {
mDisplayReadyLocked = false;
}
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
// 通知更新亮度
sendUpdatePowerStateLocked();
}
return mDisplayReadyLocked;
}
}
自动背光调节的流程调用是从 updateBrightness() 开始,最终也是调用 sendUpdatePowerStateLocked,如下
@Override
public void updateBrightness() {
sendUpdatePowerState();
}
private void sendUpdatePowerState() {
synchronized (mLock) {
sendUpdatePowerStateLocked();
}
}
sendUpdatePowerStateLocked 这个函数就是手动、自动亮度调节最终统一的地方。它里面只是简单的通过handler 发送调用 updatePowerState();updatePowerState() 里面才是真正进行操作的地方。
private void updatePowerState() {
// Update the power state request.
... ...
// P-Sensor的靠近操作
if (mProximitySensor != null) {
... ...
} else {
mWaitingForNegativeProximity = false;
}
if (mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF;
}
// 配置自动亮度值
boolean slowChange = false;
if (brightness < 0) {
if (autoBrightnessEnabled) {
// 这里就是获取 AutomaticBrightnessController 保存的自动亮度值
brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
}
if (brightness >= 0) {
// 这里就是保证 brightness 在系统最小最大设置值 10 ~ 255 之间
// 具体看 frameworks/base/core/res/res/values/config.xml 中 config_screenBrightnessSettingMinimum config_screenBrightnessSettingMaximum 值
brightness = clampScreenBrightness(brightness);
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
mAppliedAutoBrightness = true;
} else {
mAppliedAutoBrightness = false;
}
} else {
mAppliedAutoBrightness = false;
}
// Use default brightness when dozing unless overridden.
if (brightness < 0 && (state == Display.STATE_DOZE
|| state == Display.STATE_DOZE_SUSPEND)) {
brightness = mScreenBrightnessDozeConfig;
}
// 这里是我自己添加判断,过滤重复设置亮度
// 保存自动亮度值 mRequestPowerStateAutoBrightness。
// 如果 mRequestPowerStateChangedByUser 手动操作为false,且mRequestPowerStateAutoBrightness也没有变化,就直接return
if (mRequestPowerStateAutoBrightness != brightness) {
mRequestPowerStateAutoBrightness = brightness;
} else if (!mRequestPowerStateChangedByUser) {
Slog.d(TAG, "Brightness no changed");
return;
}
// 这里使用手动亮度值
Slog.d(TAG, "Apply manual brightness " + brightness + " " + mRequestPowerStateAutoBrightness);
if (brightness < 0 || mRequestPowerStateChangedByUser) {
int clampBrightness = clampScreenBrightness(mPowerRequest.screenBrightness);
if (brightness == clampBrightness) {
Slog.d(TAG, "RequestPowerStateChangedByUser Brightness no changed");
return;
}
brightness = clampBrightness;
}
// 这里就是系统自动休眠前,先变暗一会
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightness > mScreenBrightnessRangeMinimum) {
brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
}
if (!mAppliedDimming) {
slowChange = false;
}
mAppliedDimming = true;
} else if (mAppliedDimming) {
slowChange = false;
mAppliedDimming = false;
}
... ...
// 判断屏幕是否是off
if (!mPendingScreenOff) {
... ...
// 通过判断确定背光响应变化速度
// mBrightnessRampRateSlow 原生是60,是1s调整60亮度
// mBrightnessRampRateFast 原生是180,是1s调整180亮度
boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
if (!mRequestPowerStateChangedByUser && (state == Display.STATE_ON
&& mSkipRampState == RAMP_STATE_SKIP_NONE
|| state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig)
&& !wasOrWillBeInVr) {
// 一般自动亮度变化是会渐变调整的
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
} else {
// 手动一般是立即变化的,无需动画渐变调整的
animateScreenBrightness(brightness, 0);
}
Slog.d(TAG, "putInt brightness " + brightness);
}
... ...
}
animateScreenBrightness 内部逻辑是在 frameworks/base/services/core/java/com/android/server/display/RampAnimator.java 中 animateTo 处理。
animateTo 中调用 postAnimationCallback ,在 mAnimationCallback 中一直设置值渐变。
private void postAnimationCallback() {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
}
private void cancelAnimationCallback() {
mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
}
private final Runnable mAnimationCallback = new Runnable() {
@Override // Choreographer callback
public void run() {
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
* 0.000000001f;
mLastFrameTimeNanos = frameTimeNanos;
// Advance the animated value towards the target at the specified rate
// and clamp to the target. This gives us the new current value but
// we keep the animated value around to allow for fractional increments
// towards the target.
final float scale = ValueAnimator.getDurationScale();
if (scale == 0) {
// Animation off.
mAnimatedValue = mTargetValue;
} else {
final float amount = timeDelta * mRate / scale;
if (mTargetValue > mCurrentValue) {
mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
} else {
mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
}
}
final int oldCurrentValue = mCurrentValue;
mCurrentValue = Math.round(mAnimatedValue);
if (oldCurrentValue != mCurrentValue) {
mProperty.setValue(mObject, mCurrentValue);
}
// mCurrentValue 当前值
// mTargetValue 目标值
if (mTargetValue != mCurrentValue) {
postAnimationCallback();
} else {
mAnimating = false;
if (mListener != null) {
// 通知变化完成
mListener.onAnimationEnd();
}
}
}
};
mProperty.setValue(mObject, mCurrentValue);
这个方法就是实际操作写入背光值的地方,往下就是通过 native 调用处理。到这里背光设置就完成了。