一、一般设置
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<integer name="config_screenBrightnessSettingMinimum">2</integer>
<integer name="config_screenBrightnessDim">2</integer>
系统背光节点路径:/sys/class/leds/lcd-backlight/brightness
3、自动背光配置设置
自动背光涉及光感值与亮度值对应,需要根据项目进行设置光感和背光值数组,一一对应。
# frameworks/base/core/res/res/values/config.xml<integer-array name="config_autoBrightnessLevels">
... 填写亮度值数组 ...
</integer-array><integer-array name="config_autoBrightnessLcdBacklightValues">
... 填写光感值数组 ...
</integer-array>
二、流程分析
系统手动设置,待机休眠等都是通过 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() {@Overridepublic void onSensorChanged(SensorEvent event) {if (mLightSensorEnabled) {final long time = SystemClock.uptimeMillis();final float lux = event.values[0];handleLightSensorEvent(time, lux);}}@Overridepublic 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);}@Overridepublic 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也没有变化,就直接returnif (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;}... ...// 判断屏幕是否是offif (!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 callbackpublic 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 调用处理。到这里背光设置就完成了。