Skip to content

Commit 8b9cf1c

Browse files
author
Jeff Brown
committed
Reduce screen on latency, eliminate flashes.
Always use the ElectronBeam now, even when we are only animating the backlight so that we will have a black surface remaining on the screen after the screen turns off. When turning on the screen, keep the black surface showing until we unblock screen on then dismiss it as usual. This change eliminates the flashing of old display content when the screen is turned on. It also helps to conceal some of the latency of turning the screen on. We always turn the screen on immediately (even when screen on has nominally been blocked) and rely on the black surface to hide the screen contents until the last moment. Dismissing the black surface is practically instantaneous compared to turning the screen on. Bug: 7299370 Bug: 7139924 Change-Id: I57d13287acd05bd0a48811095bb02dc7bc7cbeb6
1 parent 138f272 commit 8b9cf1c

File tree

5 files changed

+116
-70
lines changed

5 files changed

+116
-70
lines changed

services/java/com/android/server/power/DisplayPowerController.java

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,12 @@ final class DisplayPowerController {
271271
// When the screen turns on again, we report user activity to the power manager.
272272
private boolean mScreenOffBecauseOfProximity;
273273

274+
// True if the screen on is being blocked.
275+
private boolean mScreenOnWasBlocked;
276+
277+
// The elapsed real time when the screen on was blocked.
278+
private long mScreenOnBlockStartRealTime;
279+
274280
// Set to true if the light sensor is enabled.
275281
private boolean mLightSensorEnabled;
276282

@@ -513,7 +519,7 @@ private void initialize() {
513519
final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
514520
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
515521
mPowerState = new DisplayPowerState(
516-
mElectronBeamAnimatesBacklightConfig ? null : new ElectronBeam(display),
522+
new ElectronBeam(display),
517523
new PhotonicModulator(executor,
518524
mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
519525
mSuspendBlocker));
@@ -553,7 +559,6 @@ private void updatePowerState() {
553559
final boolean mustNotify;
554560
boolean mustInitialize = false;
555561
boolean updateAutoBrightness = mTwilightChanged;
556-
boolean screenOnWasBlocked = false;
557562
mTwilightChanged = false;
558563

559564
synchronized (mLock) {
@@ -662,18 +667,24 @@ private void updatePowerState() {
662667
// It is relatively short but if we cancel it and switch to the
663668
// on animation immediately then the results are pretty ugly.
664669
if (!mElectronBeamOffAnimator.isStarted()) {
665-
if (mPowerRequest.blockScreenOn && !mPowerState.isScreenOn()) {
666-
if (DEBUG) {
667-
Slog.d(TAG, "Blocked screen on while screen currently off.");
668-
}
669-
screenOnWasBlocked = true;
670+
// Turn the screen on. The contents of the screen may not yet
671+
// be visible if the electron beam has not been dismissed because
672+
// its last frame of animation is solid black.
673+
setScreenOn(true);
674+
675+
if (mPowerRequest.blockScreenOn
676+
&& mPowerState.getElectronBeamLevel() == 0.0f) {
677+
blockScreenOn();
670678
} else {
671-
setScreenOn(true);
679+
unblockScreenOn();
672680
if (USE_ELECTRON_BEAM_ON_ANIMATION) {
673681
if (!mElectronBeamOnAnimator.isStarted()) {
674682
if (mPowerState.getElectronBeamLevel() == 1.0f) {
675683
mPowerState.dismissElectronBeam();
676-
} else if (mPowerState.prepareElectronBeam(true)) {
684+
} else if (mPowerState.prepareElectronBeam(
685+
mElectronBeamAnimatesBacklightConfig ?
686+
ElectronBeam.MODE_BLANK :
687+
ElectronBeam.MODE_WARM_UP)) {
677688
mElectronBeamOnAnimator.start();
678689
} else {
679690
mElectronBeamOnAnimator.end();
@@ -684,22 +695,6 @@ private void updatePowerState() {
684695
mPowerState.dismissElectronBeam();
685696
}
686697
}
687-
} else {
688-
// FIXME: If the electron beam off animation is playing then we have a bit
689-
// of a problem. The window manager policy would only have requested
690-
// to block screen on if it was about to start preparing the keyguard.
691-
// It's already too late to do anything about that. Ideally we would
692-
// let the animation play out first but that would require making
693-
// some pretty deep changes to the power manager and we don't have
694-
// time just now. For now, short-circuit the animation and get ready.
695-
if (mPowerRequest.blockScreenOn) {
696-
if (DEBUG) {
697-
Slog.d(TAG, "Blocked screen on while screen off animation running.");
698-
}
699-
screenOnWasBlocked = true;
700-
setScreenOn(false);
701-
mElectronBeamOffAnimator.end();
702-
}
703698
}
704699
} else {
705700
// Want screen off.
@@ -708,7 +703,10 @@ private void updatePowerState() {
708703
if (!mElectronBeamOffAnimator.isStarted()) {
709704
if (mPowerState.getElectronBeamLevel() == 0.0f) {
710705
setScreenOn(false);
711-
} else if (mPowerState.prepareElectronBeam(false)
706+
} else if (mPowerState.prepareElectronBeam(
707+
mElectronBeamAnimatesBacklightConfig ?
708+
ElectronBeam.MODE_BLANK :
709+
ElectronBeam.MODE_COOL_DOWN)
712710
&& mPowerState.isScreenOn()) {
713711
mElectronBeamOffAnimator.start();
714712
} else {
@@ -723,7 +721,7 @@ private void updatePowerState() {
723721
// We mostly care about the screen state here, ignoring brightness changes
724722
// which will be handled asynchronously.
725723
if (mustNotify
726-
&& !screenOnWasBlocked
724+
&& !mScreenOnWasBlocked
727725
&& !mElectronBeamOnAnimator.isStarted()
728726
&& !mElectronBeamOffAnimator.isStarted()
729727
&& mPowerState.waitUntilClean(mCleanListener)) {
@@ -740,6 +738,26 @@ private void updatePowerState() {
740738
}
741739
}
742740

741+
private void blockScreenOn() {
742+
if (!mScreenOnWasBlocked) {
743+
mScreenOnWasBlocked = true;
744+
if (DEBUG) {
745+
Slog.d(TAG, "Blocked screen on.");
746+
mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
747+
}
748+
}
749+
}
750+
751+
private void unblockScreenOn() {
752+
if (mScreenOnWasBlocked) {
753+
mScreenOnWasBlocked = false;
754+
if (DEBUG) {
755+
Slog.d(TAG, "Unblocked screen on after " +
756+
(SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
757+
}
758+
}
759+
}
760+
743761
private void setScreenOn(boolean on) {
744762
if (!mPowerState.isScreenOn() == on) {
745763
mPowerState.setScreenOn(on);

services/java/com/android/server/power/DisplayPowerRequest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,14 @@ final class DisplayPowerRequest {
5252
// If true, enables automatic brightness control.
5353
public boolean useAutoBrightness;
5454

55-
// If true, prevents the screen from turning on if it is currently off.
56-
// The display does not enter a "ready" state if this flag is true and the screen
57-
// is off and is being prevented from turning on. The window manager policy blocks
58-
// screen on while it prepares the keyguard to prevent the user from seeing
59-
// intermediate updates.
55+
// If true, prevents the screen from completely turning on if it is currently off.
56+
// The display does not enter a "ready" state if this flag is true and screen on is
57+
// blocked. The window manager policy blocks screen on while it prepares the keyguard to
58+
// prevent the user from seeing intermediate updates.
59+
//
60+
// Technically, we may not block the screen itself from turning on (because that introduces
61+
// extra unnecessary latency) but we do prevent content on screen from becoming
62+
// visible to the user.
6063
public boolean blockScreenOn;
6164

6265
public DisplayPowerRequest() {

services/java/com/android/server/power/DisplayPowerState.java

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ final class DisplayPowerState {
5050
private static final int DIRTY_BRIGHTNESS = 1 << 2;
5151

5252
private final Choreographer mChoreographer;
53-
private final ElectronBeam mElectronBeam; // may be null if only animating backlights
53+
private final ElectronBeam mElectronBeam;
5454
private final PhotonicModulator mScreenBrightnessModulator;
5555

5656
private int mDirty;
@@ -130,26 +130,19 @@ public boolean isScreenOn() {
130130
* This method should be called before starting an animation because it
131131
* can take a fair amount of time to prepare the electron beam surface.
132132
*
133-
* @param warmUp True if the electron beam should start warming up.
133+
* @param mode The electron beam animation mode to prepare.
134134
* @return True if the electron beam was prepared.
135135
*/
136-
public boolean prepareElectronBeam(boolean warmUp) {
137-
if (mElectronBeam != null) {
138-
boolean success = mElectronBeam.prepare(warmUp);
139-
invalidate(DIRTY_ELECTRON_BEAM);
140-
return success;
141-
} else {
142-
return true;
143-
}
136+
public boolean prepareElectronBeam(int mode) {
137+
invalidate(DIRTY_ELECTRON_BEAM);
138+
return mElectronBeam.prepare(mode);
144139
}
145140

146141
/**
147142
* Dismisses the electron beam surface.
148143
*/
149144
public void dismissElectronBeam() {
150-
if (mElectronBeam != null) {
151-
mElectronBeam.dismiss();
152-
}
145+
mElectronBeam.dismiss();
153146
}
154147

155148
/**
@@ -230,9 +223,7 @@ public void dump(PrintWriter pw) {
230223
pw.println(" mScreenBrightness=" + mScreenBrightness);
231224
pw.println(" mElectronBeamLevel=" + mElectronBeamLevel);
232225

233-
if (mElectronBeam != null) {
234-
mElectronBeam.dump(pw);
235-
}
226+
mElectronBeam.dump(pw);
236227
}
237228

238229
private void invalidate(int dirty) {
@@ -251,7 +242,7 @@ private void apply() {
251242
PowerManagerService.nativeSetScreenState(false);
252243
}
253244

254-
if ((mDirty & DIRTY_ELECTRON_BEAM) != 0 && mElectronBeam != null) {
245+
if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) {
255246
mElectronBeam.draw(mElectronBeamLevel);
256247
}
257248

0 commit comments

Comments
 (0)