* commit 'f0245cb2e3058e74ad1df7a169ae663d31565ce5': Reduce latency from doze to screen on.
This commit is contained in:
@@ -227,6 +227,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
|||||||
// turning off the screen.
|
// turning off the screen.
|
||||||
private boolean mPendingScreenOff;
|
private boolean mPendingScreenOff;
|
||||||
|
|
||||||
|
// True if we have unfinished business and are holding a suspend blocker.
|
||||||
|
private boolean mUnfinishedBusiness;
|
||||||
|
|
||||||
// The elapsed real time when the screen on was blocked.
|
// The elapsed real time when the screen on was blocked.
|
||||||
private long mScreenOnBlockStartRealTime;
|
private long mScreenOnBlockStartRealTime;
|
||||||
|
|
||||||
@@ -633,22 +636,42 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
|||||||
mAppliedLowPower = true;
|
mAppliedLowPower = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animate the screen brightness when the screen is on.
|
|
||||||
if (state != Display.STATE_OFF) {
|
|
||||||
animateScreenBrightness(brightness, slowChange
|
|
||||||
? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animate the screen state change unless already animating.
|
// Animate the screen state change unless already animating.
|
||||||
animateScreenStateChange(state, performScreenOffTransition);
|
animateScreenStateChange(state, performScreenOffTransition);
|
||||||
|
|
||||||
// Report whether the display is ready for use and all changes have been applied.
|
// Animate the screen brightness when the screen is on or dozing.
|
||||||
if (mustNotify
|
// Skip the animation when the screen is off or suspended.
|
||||||
&& mPendingScreenOnUnblocker == null
|
final int actualState = mPowerState.getScreenState();
|
||||||
|
if (actualState == Display.STATE_ON || actualState == Display.STATE_DOZE) {
|
||||||
|
animateScreenBrightness(brightness,
|
||||||
|
slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
|
||||||
|
} else {
|
||||||
|
animateScreenBrightness(brightness, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether the display is ready for use in the newly requested state.
|
||||||
|
// Note that we do not wait for the brightness ramp animation to complete before
|
||||||
|
// reporting the display is ready because we only need to ensure the screen is in the
|
||||||
|
// right power state even as it continues to converge on the desired brightness.
|
||||||
|
final boolean ready = mPendingScreenOnUnblocker == null
|
||||||
&& !mColorFadeOnAnimator.isStarted()
|
&& !mColorFadeOnAnimator.isStarted()
|
||||||
&& !mColorFadeOffAnimator.isStarted()
|
&& !mColorFadeOffAnimator.isStarted()
|
||||||
&& !mScreenBrightnessRampAnimator.isAnimating()
|
&& mPowerState.waitUntilClean(mCleanListener);
|
||||||
&& mPowerState.waitUntilClean(mCleanListener)) {
|
final boolean finished = ready
|
||||||
|
&& !mScreenBrightnessRampAnimator.isAnimating();
|
||||||
|
|
||||||
|
// Grab a wake lock if we have unfinished business.
|
||||||
|
if (!finished && !mUnfinishedBusiness) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Unfinished business...");
|
||||||
|
}
|
||||||
|
mCallbacks.acquireSuspendBlocker();
|
||||||
|
mUnfinishedBusiness = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the power manager when ready.
|
||||||
|
if (ready && mustNotify) {
|
||||||
|
// Send state change.
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (!mPendingRequestChangedLocked) {
|
if (!mPendingRequestChangedLocked) {
|
||||||
mDisplayReadyLocked = true;
|
mDisplayReadyLocked = true;
|
||||||
@@ -660,6 +683,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
|||||||
}
|
}
|
||||||
sendOnStateChangedWithWakelock();
|
sendOnStateChangedWithWakelock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release the wake lock when we have no unfinished business.
|
||||||
|
if (finished && mUnfinishedBusiness) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Finished business...");
|
||||||
|
}
|
||||||
|
mUnfinishedBusiness = false;
|
||||||
|
mCallbacks.releaseSuspendBlocker();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -723,6 +755,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void animateScreenBrightness(int target, int rate) {
|
private void animateScreenBrightness(int target, int rate) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
|
||||||
|
}
|
||||||
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
|
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
|
||||||
try {
|
try {
|
||||||
mBatteryStats.noteScreenBrightness(target);
|
mBatteryStats.noteScreenBrightness(target);
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ final class DisplayPowerState {
|
|||||||
mBacklight = backlight;
|
mBacklight = backlight;
|
||||||
mColorFade = electronBeam;
|
mColorFade = electronBeam;
|
||||||
mPhotonicModulator = new PhotonicModulator();
|
mPhotonicModulator = new PhotonicModulator();
|
||||||
|
mPhotonicModulator.start();
|
||||||
|
|
||||||
// At boot time, we know that the screen is on and the electron beam
|
// At boot time, we know that the screen is on and the electron beam
|
||||||
// animation is not playing. We don't know the screen's brightness though,
|
// animation is not playing. We don't know the screen's brightness though,
|
||||||
@@ -336,7 +337,7 @@ final class DisplayPowerState {
|
|||||||
/**
|
/**
|
||||||
* Updates the state of the screen and backlight asynchronously on a separate thread.
|
* Updates the state of the screen and backlight asynchronously on a separate thread.
|
||||||
*/
|
*/
|
||||||
private final class PhotonicModulator {
|
private final class PhotonicModulator extends Thread {
|
||||||
private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
|
private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
|
||||||
private static final int INITIAL_BACKLIGHT = -1; // unknown
|
private static final int INITIAL_BACKLIGHT = -1; // unknown
|
||||||
|
|
||||||
@@ -361,7 +362,7 @@ final class DisplayPowerState {
|
|||||||
|
|
||||||
if (!mChangeInProgress) {
|
if (!mChangeInProgress) {
|
||||||
mChangeInProgress = true;
|
mChangeInProgress = true;
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask);
|
mLock.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !mChangeInProgress;
|
return !mChangeInProgress;
|
||||||
@@ -369,75 +370,78 @@ final class DisplayPowerState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dump(PrintWriter pw) {
|
public void dump(PrintWriter pw) {
|
||||||
pw.println();
|
synchronized (mLock) {
|
||||||
pw.println("Photonic Modulator State:");
|
pw.println();
|
||||||
pw.println(" mPendingState=" + Display.stateToString(mPendingState));
|
pw.println("Photonic Modulator State:");
|
||||||
pw.println(" mPendingBacklight=" + mPendingBacklight);
|
pw.println(" mPendingState=" + Display.stateToString(mPendingState));
|
||||||
pw.println(" mActualState=" + Display.stateToString(mActualState));
|
pw.println(" mPendingBacklight=" + mPendingBacklight);
|
||||||
pw.println(" mActualBacklight=" + mActualBacklight);
|
pw.println(" mActualState=" + Display.stateToString(mActualState));
|
||||||
pw.println(" mChangeInProgress=" + mChangeInProgress);
|
pw.println(" mActualBacklight=" + mActualBacklight);
|
||||||
|
pw.println(" mChangeInProgress=" + mChangeInProgress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Runnable mTask = new Runnable() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public void run() {
|
for (;;) {
|
||||||
// Apply pending changes until done.
|
// Get pending change.
|
||||||
for (;;) {
|
final int state;
|
||||||
final int state;
|
final boolean stateChanged;
|
||||||
final boolean stateChanged;
|
final int backlight;
|
||||||
final int backlight;
|
final boolean backlightChanged;
|
||||||
final boolean backlightChanged;
|
synchronized (mLock) {
|
||||||
synchronized (mLock) {
|
state = mPendingState;
|
||||||
state = mPendingState;
|
stateChanged = (state != mActualState);
|
||||||
stateChanged = (state != mActualState);
|
backlight = mPendingBacklight;
|
||||||
backlight = mPendingBacklight;
|
backlightChanged = (backlight != mActualBacklight);
|
||||||
backlightChanged = (backlight != mActualBacklight);
|
if (!stateChanged && !backlightChanged) {
|
||||||
if (!stateChanged && !backlightChanged) {
|
// All changed applied, notify outer class and wait for more.
|
||||||
mChangeInProgress = false;
|
mChangeInProgress = false;
|
||||||
break;
|
postScreenUpdateThreadSafe();
|
||||||
}
|
try {
|
||||||
mActualState = state;
|
mLock.wait();
|
||||||
mActualBacklight = backlight;
|
} catch (InterruptedException ex) { }
|
||||||
}
|
continue;
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "Updating screen state: state="
|
|
||||||
+ Display.stateToString(state) + ", backlight=" + backlight);
|
|
||||||
}
|
|
||||||
boolean suspending = Display.isSuspendedState(state);
|
|
||||||
if (stateChanged && !suspending) {
|
|
||||||
requestDisplayState(state);
|
|
||||||
}
|
|
||||||
if (backlightChanged) {
|
|
||||||
setBrightness(backlight);
|
|
||||||
}
|
|
||||||
if (stateChanged && suspending) {
|
|
||||||
requestDisplayState(state);
|
|
||||||
}
|
}
|
||||||
|
mActualState = state;
|
||||||
|
mActualBacklight = backlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let the outer class know that all changes have been applied.
|
// Apply pending change.
|
||||||
postScreenUpdateThreadSafe();
|
if (DEBUG) {
|
||||||
}
|
Slog.d(TAG, "Updating screen state: state="
|
||||||
|
+ Display.stateToString(state) + ", backlight=" + backlight);
|
||||||
private void requestDisplayState(int state) {
|
}
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
|
boolean suspending = Display.isSuspendedState(state);
|
||||||
+ Display.stateToString(state) + ")");
|
if (stateChanged && !suspending) {
|
||||||
try {
|
requestDisplayState(state);
|
||||||
mBlanker.requestDisplayState(state);
|
}
|
||||||
} finally {
|
if (backlightChanged) {
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_POWER);
|
setBrightness(backlight);
|
||||||
|
}
|
||||||
|
if (stateChanged && suspending) {
|
||||||
|
requestDisplayState(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setBrightness(int backlight) {
|
private void requestDisplayState(int state) {
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
|
Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
|
||||||
try {
|
+ Display.stateToString(state) + ")");
|
||||||
mBacklight.setBrightness(backlight);
|
try {
|
||||||
} finally {
|
mBlanker.requestDisplayState(state);
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_POWER);
|
} finally {
|
||||||
}
|
Trace.traceEnd(Trace.TRACE_TAG_POWER);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
private void setBrightness(int backlight) {
|
||||||
|
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
|
||||||
|
try {
|
||||||
|
mBacklight.setBrightness(backlight);
|
||||||
|
} finally {
|
||||||
|
Trace.traceEnd(Trace.TRACE_TAG_POWER);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,20 +50,32 @@ final class RampAnimator<T> {
|
|||||||
/**
|
/**
|
||||||
* Starts animating towards the specified value.
|
* Starts animating towards the specified value.
|
||||||
*
|
*
|
||||||
* If this is the first time the property is being set, the value jumps
|
* If this is the first time the property is being set or if the rate is 0,
|
||||||
* directly to the target.
|
* the value jumps directly to the target.
|
||||||
*
|
*
|
||||||
* @param target The target value.
|
* @param target The target value.
|
||||||
* @param rate The convergence rate, in units per second.
|
* @param rate The convergence rate in units per second, or 0 to set the value immediately.
|
||||||
* @return True if the target differs from the previous target.
|
* @return True if the target differs from the previous target.
|
||||||
*/
|
*/
|
||||||
public boolean animateTo(int target, int rate) {
|
public boolean animateTo(int target, int rate) {
|
||||||
// Immediately jump to the target the first time.
|
// Immediately jump to the target the first time.
|
||||||
if (mFirstTime) {
|
if (mFirstTime || rate <= 0) {
|
||||||
mFirstTime = false;
|
if (mFirstTime || target != mCurrentValue) {
|
||||||
mProperty.setValue(mObject, target);
|
mFirstTime = false;
|
||||||
mCurrentValue = target;
|
mRate = 0;
|
||||||
return true;
|
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.
|
// Adjust the rate based on the closest target.
|
||||||
@@ -88,7 +100,7 @@ final class RampAnimator<T> {
|
|||||||
mAnimating = true;
|
mAnimating = true;
|
||||||
mAnimatedValue = mCurrentValue;
|
mAnimatedValue = mCurrentValue;
|
||||||
mLastFrameTimeNanos = System.nanoTime();
|
mLastFrameTimeNanos = System.nanoTime();
|
||||||
postCallback();
|
postAnimationCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
@@ -108,11 +120,15 @@ final class RampAnimator<T> {
|
|||||||
mListener = listener;
|
mListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postCallback() {
|
private void postAnimationCallback() {
|
||||||
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null);
|
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Runnable mCallback = new Runnable() {
|
private void cancelAnimationCallback() {
|
||||||
|
mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Runnable mAnimationCallback = new Runnable() {
|
||||||
@Override // Choreographer callback
|
@Override // Choreographer callback
|
||||||
public void run() {
|
public void run() {
|
||||||
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
|
final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
|
||||||
@@ -144,7 +160,7 @@ final class RampAnimator<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mTargetValue != mCurrentValue) {
|
if (mTargetValue != mCurrentValue) {
|
||||||
postCallback();
|
postAnimationCallback();
|
||||||
} else {
|
} else {
|
||||||
mAnimating = false;
|
mAnimating = false;
|
||||||
if (mListener != null) {
|
if (mListener != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user