上一篇博客我们主要分析了在setScreenState中调用PhoneWindowManager的一些流程,在setScreenState中先是调用了DisplayPowerState的setScreenState函数。上篇博客我们没有分析,这篇博客我们先从这个函数开始分析,主要分析下亮度的设置流程。
-
public void setScreenState(int state) {
-
if (mScreenState != state) {
-
if (DEBUG) {
-
Slog.d(TAG,
“setScreenState: state=” + state);
-
}
-
-
mScreenState = state;
-
mScreenReady =
false;
-
scheduleScreenUpdate();
-
}
-
}
scheduleScreenUpdate主要通过消息方式,最后调用到下面函数。当我们屏幕刚要点亮,这个时候mScreenBrightness为0,所以这个时候调用mPhotonicModulator.setState设置state是点亮,但是brightness是0的。
-
private final Runnable mScreenUpdateRunnable =
new Runnable() {
-
@Override
-
public
void run() {
-
mScreenUpdatePending =
false;
-
-
int brightness = mScreenState != Display.STATE_OFF
-
&& mColorFadeLevel >
0f ? mScreenBrightness :
0;
-
if (mPhotonicModulator.setState(mScreenState, brightness)) {
-
if (DEBUG) {
-
Slog.d(TAG,
"Screen ready");
-
}
-
mScreenReady =
true;
-
invokeCleanListenerIfNeeded();
-
}
else {
-
if (DEBUG) {
-
Slog.d(TAG,
"Screen not ready");
-
}
-
}
-
}
-
};
DisplayPowerState的设置亮度状态逻辑分析
mPhotonicModulator.setState应该要PhotonicModulator的run函数结合一起看。
-
public boolean setState(int state, int backlight) {
-
synchronized (mLock) {
-
boolean stateChanged = state != mPendingState;
-
boolean backlightChanged = backlight != mPendingBacklight;
-
if (stateChanged || backlightChanged) {
-
if (DEBUG) {
-
Slog.d(TAG,
"Requesting new screen state: state="
-
+ Display.stateToString(state) +
", backlight=" + backlight);
-
}
-
-
mPendingState = state;
-
mPendingBacklight = backlight;
-
-
boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
-
mStateChangeInProgress = stateChanged;
-
mBacklightChangeInProgress = backlightChanged;
-
-
if (!changeInProgress) {
-
Slog.d(TAG,
"notify set backlight thread run");
-
mLock.notifyAll();
-
}
-
}
-
return !mStateChangeInProgress;
-
}
-
}
两者结合看先setState设置了状态,只有状态改变时,我们才能重新设置状态(设置到mpendingState和mPendingBacklight)。而在run函数中,当设置的状态mPendingState、mPendingBacklight和mActualState、mActualBacklight(真正设置到背光的状态、亮度)不一样时,才会调用mBlanker.requestDisplayState设置亮度。否则状态没有改变,就会把mStateChangeInProgress 和mBacklightChangeInProgress 设置为false,然后线程就wait住。
而此时setState重新设置下来的话,这个时候把亮度和状态设置到mPendingState 和mPendingBacklight 。然后这时mStateChangeInProgress 和 mBacklightChangeInProgress都是false。这样就可以调用mLock的notifyAll函数重新唤醒线程,这样就把把前面setState设置下来的mPendingState和mPendingBacklight再通过mBlanker.requestDisplayState设置到背光设备中去。
-
@
Override
-
public
void
run
() {
-
for (;;) {
-
// Get pending change.
-
final
int state;
-
final boolean stateChanged;
-
final
int backlight;
-
final boolean backlightChanged;
-
synchronized (mLock) {
-
state = mPendingState;
-
stateChanged = (state != mActualState);
-
backlight = mPendingBacklight;
-
backlightChanged = (backlight != mActualBacklight);
-
if (!stateChanged) {
-
// State changed applied, notify outer class.
-
postScreenUpdateThreadSafe();
-
mStateChangeInProgress =
false;
-
}
-
if (!backlightChanged) {
-
mBacklightChangeInProgress =
false;
-
}
-
if (!stateChanged && !backlightChanged) {
-
try {
-
mLock.wait();
-
}
catch (InterruptedException ex) { }
-
continue;
-
}
-
mActualState = state;
-
mActualBacklight = backlight;
-
}
-
-
// Apply pending change.
-
if (
true) {
-
Slog.d(TAG,
"Updating screen state: state="
-
+ Display.stateToString(state) +
", backlight=" + backlight);
-
}
-
mBlanker.requestDisplayState(state, backlight);
-
Slog.d(TAG,
"kangchen Updating screen state: state=");
-
}
-
}
设置亮度、状态到背光设备
DisplayBlanker的requestDisplayState如下,主要调用requestGlobalDisplayStateInternal函数。
-
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);
-
}
-
}
-
};
requestGlobalDisplayStateInternal函数先是对state和brightness的处理,然后把这个两个变量放在mGlobalDisplayState 和mGlobalDisplayBrightness成员变量中。紧接着调用applyGlobalDisplayStateLocked函数mTempDisplayStateWorkQueue作为参数。最后再调用mTempDisplayStateWorkQueue各个成员的run函数(这里返回的是Runnable接口,这里就会设置状态和亮度到设备中去)。
-
private void requestGlobalDisplayStateInternal(int state, int brightness) {
-
if (state == Display.STATE_UNKNOWN) {
-
state = Display.STATE_ON;
-
}
-
if (state == Display.STATE_OFF) {
-
brightness = PowerManager.BRIGHTNESS_OFF;
-
}
else
if (brightness <
0) {
-
brightness = PowerManager.BRIGHTNESS_DEFAULT;
-
}
else
if (brightness > PowerManager.BRIGHTNESS_ON) {
-
brightness = PowerManager.BRIGHTNESS_ON;
-
}
-
-
synchronized (mTempDisplayStateWorkQueue) {
-
try {
-
synchronized (mSyncRoot) {
-
if (mGlobalDisplayState == state
-
&& mGlobalDisplayBrightness == brightness) {
-
return;
// no change
-
}
-
-
mGlobalDisplayState = state;
-
mGlobalDisplayBrightness = brightness;
-
applyGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
-
}
-
-
// Setting the display power state can take hundreds of milliseconds
-
// to complete so we defer the most expensive part of the work until
-
// after we have exited the critical section to avoid blocking other
-
// threads for a long time.
-
for (
int i =
0; i < mTempDisplayStateWorkQueue.size(); i++) {
-
mTempDisplayStateWorkQueue.get(i).run();
//设置亮度、状态到设备
-
}
-
} finally {
-
mTempDisplayStateWorkQueue.clear();
-
}
-
}
-
}
applyGlobalDisplayStateLocked函数会遍历各个显示设备(多显示),然后调用updateDisplayStateLocked函数返回一个Runnable,最后把这个Runnable放入之前传入的mTempDisplayStateWorkQueue队列中。
-
private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
-
final
int count = mDisplayDevices.size();
-
for (
int i =
0; i < count; i++) {
-
DisplayDevice device = mDisplayDevices.get(i);
-
Runnable runnable = updateDisplayStateLocked(device);
-
if (runnable != null) {
-
workQueue.add(runnable);
-
}
-
}
-
}
那下面我们看下updateDisplayStateLocked函数,主要是调用了DisplayDevice的requestDisplayStateLocked函数,当然mGlobalDisplayState和mGlobalDisplayBrightness作为参数。
-
private Runnable updateDisplayStateLocked(DisplayDevice device) {
-
// Blank or unblank the display immediately to match the state requested
-
// by the display power controller (if known).
-
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
-
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) ==
0) {
-
return device.requestDisplayStateLocked(mGlobalDisplayState, mGlobalDisplayBrightness);
-
}
-
return null;
-
}
这里的DisplayDevice的requestDisplayStateLocked函数,是在LocalDisplayAdapter中实现的,这里吧state和brightness保存在mState和mBrightness中,然后返回Runnable接口,最后在Runnable接口中设置亮度和状态。
-
public Runnable requestDisplayStateLocked(final int state, final int brightness) {
-
// Assume that the brightness is off if the display is being turned off.
-
assert state != Display.STATE_OFF || brightness == PowerManager.BRIGHTNESS_OFF;
-
-
final boolean stateChanged = (mState != state);
-
final boolean brightnessChanged = (mBrightness != brightness) && mBacklight != null;
-
if (stateChanged || brightnessChanged) {
-
final
int displayId = mBuiltInDisplayId;
-
final IBinder token = getDisplayTokenLocked();
-
final
int oldState = mState;
-
-
if (stateChanged) {
-
mState = state;
//保存state
-
updateDeviceInfoLocked();
-
}
-
-
if (brightnessChanged) {
-
mBrightness = brightness;
//保存brightness
-
}
-
-
// Defer actually setting the display state until after we have exited
-
// the critical section since it can take hundreds of milliseconds
-
// to complete.
-
return
new Runnable() {
//返回Runnable
-
@Override
-
public
void run() {
-
// Exit a suspended state before making any changes.
-
int currentState = oldState;
-
if (Display.isSuspendedState(oldState)
-
|| oldState == Display.STATE_UNKNOWN) {
-
if (!Display.isSuspendedState(state)) {
-
setDisplayState(state);
-
currentState = state;
-
}
else
if (state == Display.STATE_DOZE_SUSPEND
-
|| oldState == Display.STATE_DOZE_SUSPEND) {
-
setDisplayState(Display.STATE_DOZE);
-
currentState = Display.STATE_DOZE;
-
}
else {
-
return;
// old state and new state is off
-
}
-
}
-
-
// Apply brightness changes given that we are in a non-suspended state.
-
if (brightnessChanged) {
-
Slog.d(TAG,
"setDisplayBrightnessbrightness1=" + brightness);
-
setDisplayBrightness(brightness);
-
Slog.d(TAG,
"setDisplayBrightnessbrightness2=" + brightness);
-
}
-
-
// Enter the final desired state, possibly suspended.
-
if (state != currentState) {
-
setDisplayState(state);
-
}
-
}
-
-
private void setDisplayState(int state) {
-
if (DEBUG) {
-
Slog.d(TAG,
"setDisplayState("
-
+
"id=" + displayId
-
+
", state=" + Display.stateToString(state) +
")");
-
}
-
try {
-
final
int mode = getPowerModeForState(state);
-
SurfaceControl.setDisplayPowerMode(token, mode);
//到SurfaceControl设置状态
-
} finally {
-
Trace.traceEnd(Trace.TRACE_TAG_POWER);
-
}
-
}
-
-
private void setDisplayBrightness(int brightness) {
-
try {
-
mBacklight.setBrightness(brightness);
//设置亮度
-
} finally {
-
Trace.traceEnd(Trace.TRACE_TAG_POWER);
-
}
-
}
-
};
-
}
-
return null;
-
}
DisplayPowerControl设置亮度逻辑(根据VSync信号将亮度慢慢变亮)
上面在DisplayPowerState中仅仅是设置状态,比如刚点亮屏幕这个时候其实设置的brightness为0,我们继续分析DisplayPowerState的updatePowerState函数。在updatePowerState函数中,当设置亮度时会调用如下代码:
-
if (!mPendingScreenOff) {
-
if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
-
animateScreenBrightness(brightness,
-
slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
-
}
else {
-
animateScreenBrightness(brightness,
0);
-
}
-
}
我们注意到这里有一个BRIGHTNESS_RAMP_RATE_SLOW 和BRIGHTNESS_RAMP_RATE_FAST(这里涉及到亮度显示原理我们后面分析),先看animateScreenBrightness函数。这里函数主要调用了mScreenBrightnessRampAnimator.animateTo函数。
-
private void animateScreenBrightness(int target, int rate) {
-
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
-
try {
-
mBatteryStats.noteScreenBrightness(target);
-
}
catch (RemoteException ex) {
-
// same process
-
}
-
}
-
}
我们再来看mScreenBrightnessRampAnimator 对象的创建
-
mScreenBrightnessRampAnimator =
new RampAnimator<DisplayPowerState>(
-
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
我们注意一个参数是DisplayPowerState对象mPowerState,另一个参数是DisplayPowerState.SCREEN_BRIGHTNESS
-
public
static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS =
-
new IntProperty<DisplayPowerState>(
"screenBrightness") {
-
@Override
-
public
void setValue(DisplayPowerState object,
int value) {
-
object.setScreenBrightness(value);
-
}
-
-
@
Override
-
public Integer
get
(DisplayPowerState object) {
-
return object.getScreenBrightness();
-
}
-
};
RampAnimator的构造函数。
-
public RampAnimator(T object, IntProperty<T> property) {
-
mObject = object;
-
mProperty = property;
-
mChoreographer = Choreographer.getInstance();
-
}
我们结合RampAnimator的构造函数,再来分析RampAnimator的animateTo函数。
1. 当rate<=0时,这个时候,我们直接调用mProperty.setValue。就是调用DisplayPowerState的setScreenBrightness函数。这个setScreenBrightness函数我们后面分析。
2. 当rate>0时,这个时候会调用postAnimationCallback函数(这个函数根据VSync信号过来,把亮度慢慢上升的一个过程),而且mAnimating置为true。
-
public boolean animateTo(int target, int rate) {
-
// Immediately jump to the target the first time.
-
if (mFirstTime || rate <=
0) {
-
if (mFirstTime || target != mCurrentValue) {
-
mFirstTime =
false;
-
mRate =
0;
-
mTargetValue = target;
-
mCurrentValue = target;
-
mProperty.setValue(mObject, target);
//设置值
-
if (mAnimating) {
-
mAnimating =
false;
-
cancelAnimationCallback();
-
}
-
if (mListener != null) {
-
mListener.onAnimationEnd();
-
}
-
return
true;
-
}
-
return
false;
-
}
-
-
// Adjust the rate based on the closest target.
-
// If a faster rate is specified, then use the new rate so that we converge
-
// more rapidly based on the new request.
-
// If a slower rate is specified, then use the new rate only if the current
-
// value is somewhere in between the new and the old target meaning that
-
// we will be ramping in a different direction to get there.
-
// Otherwise, continue at the previous rate.
-
if (!mAnimating
-
|| rate > mRate
-
|| (target <= mCurrentValue && mCurrentValue <= mTargetValue)
-
|| (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
-
mRate = rate;
-
}
-
-
final boolean changed = (mTargetValue != target);
-
mTargetValue = target;
-
-
// Start animating.
-
if (!mAnimating && target != mCurrentValue) {
-
mAnimating =
true;
-
mAnimatedValue = mCurrentValue;
-
mLastFrameTimeNanos = System.nanoTime();
-
postAnimationCallback();
-
}
-
-
return changed;
-
}
下面我们先分析postAnimationCallback函数,这个和之前分析WMS的VSync信号类似,当VSync信号过来时,会调用mAnimationCallback函数。(可以看之前博客http://blog.csdn.net/kc58236582/article/details/53835998)
-
private void postAnimationCallback() {
-
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
-
}
那我们继续看mAnimationCallback 的run函数,这个函数当当前值和上一次值不一样,我们就调用DisplayPowerState的setScreenBrightness来设置亮度。而且当前值不是目标值,我们就继续调用postAnimationCallback函数,来设置VSync回调。最后当亮度变成目标值后,将mAnimating 置为false,代表亮度变化的动画结束了。
-
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;
-
-
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);
//设置到DisplayPowerState的setScreenBrightness函数中
-
}
-
-
if (mTargetValue != mCurrentValue) {
//当前值还不是目标值,继续设置VSync回调
-
postAnimationCallback();
-
}
else {
-
mAnimating =
false;
//否则动画标志置为false
-
if (mListener != null) {
-
mListener.onAnimationEnd();
-
}
-
}
-
}
-
}
最后我们再看下DisplayPowerState的SetScreenBrightness函数,将亮度设置到mScreenBrightness 中,当屏幕状态不为off时,调用scheduleScreenUpdate函数(所以肯定先要调用setScreenState来设置屏幕状态为on,这样才能设置屏幕亮度)。
-
public void setScreenBrightness(int brightness) {
-
if (mScreenBrightness != brightness) {
-
mScreenBrightness = brightness;
-
if (mScreenState != Display.STATE_OFF) {
-
mScreenReady =
false;
-
scheduleScreenUpdate();
-
}
-
}
-
}
scheduleScreenUpdate最后通过发消息会调用如下代码,这里状态已经是ON了,就会把刚刚设置的mScreenBrightness作为参数设置到mPhotonicModulator.setState中。流程和设置state一样了,只是一开始亮屏时,设置state时,亮度为0而已。
-
private final Runnable mScreenUpdateRunnable =
new Runnable() {
-
@Override
-
public
void run() {
-
mScreenUpdatePending =
false;
-
-
int brightness = mScreenState != Display.STATE_OFF
-
&& mColorFadeLevel >
0f ? mScreenBrightness :
0;
-
if (mPhotonicModulator.setState(mScreenState, brightness)) {
-
if (DEBUG) {
-
Slog.d(TAG,
"Screen ready");
-
}
-
mScreenReady =
true;
-
invokeCleanListenerIfNeeded();
-
}
else {
-
if (DEBUG) {
-
Slog.d(TAG,
"Screen not ready");
-
}
-
}
-
}
-
};