diff options
3 files changed, 141 insertions, 86 deletions
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index e2a548ace4ac..e3a25c066d9f 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -227,6 +227,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // turning off the screen. 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. private long mScreenOnBlockStartRealTime; @@ -633,22 +636,42 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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. animateScreenStateChange(state, performScreenOffTransition); - // Report whether the display is ready for use and all changes have been applied. - if (mustNotify - && mPendingScreenOnUnblocker == null + // Animate the screen brightness when the screen is on or dozing. + // Skip the animation when the screen is off or suspended. + 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() && !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) { if (!mPendingRequestChangedLocked) { mDisplayReadyLocked = true; @@ -660,6 +683,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } 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 @@ -723,6 +755,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void animateScreenBrightness(int target, int rate) { + if (DEBUG) { + Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate); + } if (mScreenBrightnessRampAnimator.animateTo(target, rate)) { try { mBatteryStats.noteScreenBrightness(target); diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java index a7651e42107e..fc068afd59a1 100644 --- a/services/core/java/com/android/server/display/DisplayPowerState.java +++ b/services/core/java/com/android/server/display/DisplayPowerState.java @@ -80,6 +80,7 @@ final class DisplayPowerState { mBacklight = backlight; mColorFade = electronBeam; mPhotonicModulator = new PhotonicModulator(); + mPhotonicModulator.start(); // 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, @@ -336,7 +337,7 @@ final class DisplayPowerState { /** * 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_BACKLIGHT = -1; // unknown @@ -361,7 +362,7 @@ final class DisplayPowerState { if (!mChangeInProgress) { mChangeInProgress = true; - AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask); + mLock.notifyAll(); } } return !mChangeInProgress; @@ -369,75 +370,78 @@ final class DisplayPowerState { } public void dump(PrintWriter pw) { - pw.println(); - pw.println("Photonic Modulator State:"); - pw.println(" mPendingState=" + Display.stateToString(mPendingState)); - pw.println(" mPendingBacklight=" + mPendingBacklight); - pw.println(" mActualState=" + Display.stateToString(mActualState)); - pw.println(" mActualBacklight=" + mActualBacklight); - pw.println(" mChangeInProgress=" + mChangeInProgress); + synchronized (mLock) { + pw.println(); + pw.println("Photonic Modulator State:"); + pw.println(" mPendingState=" + Display.stateToString(mPendingState)); + pw.println(" mPendingBacklight=" + mPendingBacklight); + pw.println(" mActualState=" + Display.stateToString(mActualState)); + pw.println(" mActualBacklight=" + mActualBacklight); + pw.println(" mChangeInProgress=" + mChangeInProgress); + } } - private final Runnable mTask = new Runnable() { - @Override - public void run() { - // Apply pending changes until done. - for (;;) { - 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 && !backlightChanged) { - mChangeInProgress = false; - break; - } - mActualState = state; - mActualBacklight = backlight; - } - - 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); + @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 && !backlightChanged) { + // All changed applied, notify outer class and wait for more. + mChangeInProgress = false; + postScreenUpdateThreadSafe(); + try { + mLock.wait(); + } catch (InterruptedException ex) { } + continue; } + mActualState = state; + mActualBacklight = backlight; } - // Let the outer class know that all changes have been applied. - postScreenUpdateThreadSafe(); + // Apply pending change. + 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); + } } + } - private void requestDisplayState(int state) { - Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState(" - + Display.stateToString(state) + ")"); - try { - mBlanker.requestDisplayState(state); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_POWER); - } + private void requestDisplayState(int state) { + Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState(" + + Display.stateToString(state) + ")"); + try { + mBlanker.requestDisplayState(state); + } 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); - } + private void setBrightness(int backlight) { + Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")"); + try { + mBacklight.setBrightness(backlight); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_POWER); } - }; + } } } diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java index ad1e85717ab1..d71269f9eaeb 100644 --- a/services/core/java/com/android/server/display/RampAnimator.java +++ b/services/core/java/com/android/server/display/RampAnimator.java @@ -50,20 +50,32 @@ final class RampAnimator<T> { /** * Starts animating towards the specified value. * - * If this is the first time the property is being set, the value jumps - * directly to the target. + * If this is the first time the property is being set or if the rate is 0, + * the value jumps directly to the target. * * @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. */ public boolean animateTo(int target, int rate) { // Immediately jump to the target the first time. - if (mFirstTime) { - mFirstTime = false; - mProperty.setValue(mObject, target); - mCurrentValue = target; - return true; + 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. @@ -88,7 +100,7 @@ final class RampAnimator<T> { mAnimating = true; mAnimatedValue = mCurrentValue; mLastFrameTimeNanos = System.nanoTime(); - postCallback(); + postAnimationCallback(); } return changed; @@ -108,11 +120,15 @@ final class RampAnimator<T> { mListener = listener; } - private void postCallback() { - mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null); + private void postAnimationCallback() { + mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null); + } + + private void cancelAnimationCallback() { + mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null); } - private final Runnable mCallback = new Runnable() { + private final Runnable mAnimationCallback = new Runnable() { @Override // Choreographer callback public void run() { final long frameTimeNanos = mChoreographer.getFrameTimeNanos(); @@ -144,7 +160,7 @@ final class RampAnimator<T> { } if (mTargetValue != mCurrentValue) { - postCallback(); + postAnimationCallback(); } else { mAnimating = false; if (mListener != null) { |